Qt QThread 线程创建,线程同步,线程通信 实例
1. 继承QThread, 实现run()方法, 即可创建线程。
2. 实例1 代码
myThread.h
#ifndef MYTHREAD_H #define MYTHREAD_H #include <QThread> class myThread : public QThread //myThread 线程类 { Q_OBJECT public: myThread(); void setMessage(const QString &message); void stop(); protected: void run(); //复写run()方法,里面是线程 的 主体代码 private: QString messageStr; volatile bool stopped; }; #endif // MYTHREAD_H
myThread.cpp
#include "myThread.h" #include <QDebug> myThread::myThread() { stopped = false; } void myThread::run() //实现run()方法, 隔1秒输出messageStr { while(!stopped) { qDebug() << messageStr << endl; sleep(1); } stopped = false; } void myThread::stop() { stopped = true; } void myThread::setMessage(const QString &message) { messageStr = message; }
dialog.h
#ifndef DIALOG_H #define DIALOG_H #include <QDialog> #include <QtGui> #include "myThread.h" class Dialog : public QDialog { Q_OBJECT public: Dialog(QWidget *parent = 0); ~Dialog(); protected: void closeEvent(QCloseEvent *event); private slots: void startOrStopThreadA(); void startOrStopThreadB(); private: myThread threadA; //用线程类 实例化 线程对象 myThread threadB; QPushButton *threadAButton; QPushButton *threadBButton; QPushButton *quitButton; }; #endif // DIALOG_H
dialog.cpp
#include "dialog.h" Dialog::Dialog(QWidget *parent) : QDialog(parent) { threadA.setMessage("A"); threadB.setMessage("B"); threadAButton = new QPushButton(tr("Start A")); threadBButton = new QPushButton(tr("Start B")); quitButton = new QPushButton(tr("Quit")); quitButton->setDefault(true); connect(threadAButton, SIGNAL(clicked()), this, SLOT(startOrStopThreadA())); connect(threadBButton, SIGNAL(clicked()), this, SLOT(startOrStopThreadB())); connect(quitButton, SIGNAL(clicked()), this, SLOT(close())); QHBoxLayout *hLayout = new QHBoxLayout; hLayout->addWidget(threadAButton); hLayout->addWidget(threadBButton); hLayout->addWidget(quitButton); setLayout(hLayout); } Dialog::~Dialog() { } void Dialog::startOrStopThreadA() { if( threadA.isRunning() ) { threadA.stop(); //结束线程 threadAButton->setText(tr("Start A")); } else { threadA.start(); //thread.start()开始线程 threadAButton->setText(tr("Stop A")); } } void Dialog::startOrStopThreadB() { if( threadB.isRunning() ) { threadB.stop(); threadBButton->setText(tr("Start B")); } else { threadB.start(); threadBButton->setText(tr("Stop B")); } } void Dialog::closeEvent(QCloseEvent *event) //当用户点击quit按键 或 这退出UI的时候,回调closeEvent函数 { threadA.stop(); threadB.stop(); threadA.wait(); threadB.wait(); event->accept(); //qDebug("--log--"); }
3. 线程同步
QT线程同步的类有: QMutex, QReadWriteLock, QSemaphore, QWaitcondition.
QMutext互斥锁: 可以锁住一段代码,同一时间只能有一个线程访问。
或者用简化锁QMutexLocked类, 构造函数输入QMutex并将其锁住, 析构函数将其解锁。
QReadWriteLock类, 允许多个线程读共享资源,但是只允许一个线程写共享资源。
QSemaphore 信号量 互斥量, 解决 生产者--消费者 问题
4. 利用信号槽, 主线程和子线程通信,互相发送消息。
子线程向主线程发送 每隔一秒向主线程发送累加数字, 主线程按键信息发送到子线程。。
Thread.h
#ifndef THREAD_H #define THREAD_H #include <QThread> class Thread : public QThread { Q_OBJECT private: int number; protected: void run(); public: Thread(QObject *parent=0); ~Thread(); signals: void UpdateSignal(int num); public slots: void ResetSlot(); }; #endif // THREAD_H
Thread.cpp
#include "Thread.h" Thread::Thread(QObject *parent) { number = 0; } Thread::~Thread() { } void Thread::run() { while(1) { emit UpdateSignal(number); //发送更新信号给主线程,附带参数number number++; sleep(1); } } void Thread::ResetSlot() { number = 0; emit UpdateSignal(number); //发送重置number信号 }
widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QtGui> #include "Thread.h" class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = 0); ~Widget(); private: QLabel *label; QPushButton *startButton; QPushButton *stopButton; QPushButton *resetButton; Thread *myThread; int number; signals: void ResetSignal(); public slots: void clearSlot(); void startSlot(); void stopSlot(); void updateSlot(int num); }; #endif // WIDGET_H
widget.cpp
#include "widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) { startButton = new QPushButton("start"); stopButton = new QPushButton("stop"); resetButton = new QPushButton("reset"); label = new QLabel("empty"); myThread = new Thread(); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(label); layout->addWidget(startButton); layout->addWidget(stopButton); layout->addWidget(resetButton); setLayout(layout); connect(stopButton, SIGNAL(clicked()), this, SLOT(stopSlot())); connect(startButton, SIGNAL(clicked()), this, SLOT(startSlot())); connect(resetButton, SIGNAL(clicked()), this, SLOT(clearSlot())); connect(myThread, SIGNAL(UpdateSignal(int)), this, SLOT(updateSlot(int))); //子线程发信号给主线程,更新number connect(this, SIGNAL(ResetSignal()), myThread, SLOT(ResetSlot())); //主线程发信号给子线程,重置number信号 resize(200, 200); } Widget::~Widget() { } void Widget::startSlot() { myThread->start(); } void Widget::stopSlot() { myThread->terminate(); } void Widget::updateSlot(int num) { label->setText(QString::number(num)); } void Widget::clearSlot() { emit ResetSignal(); //主线程发送重置信号 给 子线程 }