QThread類提供了一個與平臺無關的管理線程的方法。一個QThread對象管理一個線程。QThread的執行從run()函數的執行開始,在Qt自帶的QThread類中,run()函數經過調用exec()函數來啓動事件循環機制,而且在線程內部處理Qt的事件。在Qt中創建線程的主要目的就是爲了用線程來處理那些耗時的後臺操做,從而讓主界面能及時響應用戶的請求操做。QThread的使用方法有以下兩種:ide
下面經過具體的方法描述和例子來介紹兩種方法。函數
首先新建一個work類,該類重點在於其doWork槽函數,這個函數定義了線程須要作的工做,須要向其發送信號來觸發。Wrok類的頭文件中定義了所有函數,其cpp文件爲空,所以就不貼出來了。ui
Wroker.h的定義以下this
// work定義了線程要執行的工做 #ifndef WORKER_H #define WORKER_H #include <QObject> #include<QDebug> #include<QThread> class Worker:public QObject { Q_OBJECT public: Worker(QObject* parent = nullptr){} public slots: // doWork定義了線程要執行的操做 void doWork(int parameter) { qDebug()<<"receive the execute signal---------------------------------"; qDebug()<<" current thread ID:"<<QThread::currentThreadId(); // 循環一百萬次 for(int i = 0;i!=1000000;++i) { ++parameter; } // 發送結束信號 qDebug()<<" finish the work and sent the resultReady signal\n"; emit resultReady(parameter); } // 線程完成工做時發送的信號 signals: void resultReady(const int result); }; #endif // WORKER_H 1234567891011121314151617181920212223242526272829303132333435
而後定義一個Controller類,這個類中定義了一個QThread對象,用於處理worker對象的事件循環工做。spa
Controller.h的定義以下:線程
#ifndef CONTROLLER_H #define CONTROLLER_H #include <QObject> #include<QThread> #include<QDebug> // controller用於啓動線程和處理線程執行結果 class Controller : public QObject { Q_OBJECT QThread workerThread; public: Controller(QObject *parent= nullptr); ~Controller(); public slots: // 處理線程執行的結果 void handleResults(const int rslt) { qDebug()<<"receive the resultReady signal---------------------------------"; qDebug()<<" current thread ID:"<<QThread::currentThreadId()<<'\n'; qDebug()<<" the last result is:"<<rslt; } signals: // 發送信號觸發線程 void operate(const int); }; #endif // CONTROLLER_H 12345678910111213141516171819202122232425262728293031
Controller類的cpp文件,其構造函數中建立worker對象,而且將其事件循環所有交給workerThread對象來處理,最後啓動該線程,而後觸發其事件處理函數。code
controller.cpp的定義以下:對象
#include "controller.h" #include <worker.h> Controller::Controller(QObject *parent) : QObject(parent) { Worker *worker = new Worker; //調用moveToThread將該任務交給workThread worker->moveToThread(&workerThread); //operate信號發射後啓動線程工做 connect(this, SIGNAL(operate(const int)), worker, SLOT(doWork(int))); //該線程結束時銷燬 connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); //線程結束後發送信號,對結果進行處理 connect(worker, SIGNAL(resultReady(int)), this, SLOT(handleResults(int))); //啓動線程 workerThread.start(); //發射信號,開始執行 qDebug()<<"emit the signal to execute!---------------------------------"; qDebug()<<" current thread ID:"<<QThread::currentThreadId()<<'\n'; emit operate(0); } //析構函數中調用quit()函數結束線程 Controller::~Controller() { workerThread.quit(); workerThread.wait(); } 123456789101112131415161718192021222324252627
接下來就是主函數,主函數中咱們新建一個Controller對象,開始執行:blog
main.cpp的內容以下繼承
#include <QCoreApplication> #include "controller.h" #include<QDebug> #include<QThread> int main(int argc, char *argv[]) { qDebug()<<"I am main Thread, my ID:"<<QThread::currentThreadId()<<"\n"; QCoreApplication a(argc, argv); Controller c; return a.exec(); } 123456789101112
運行結果截圖 1
main函數中打印當前線程編號,即主線程的線程編號是0X7a4, 在Controller的構造函數中繼續打印當前線程編號,也是主線程編號,以後把work類的工做交給子線程後,給子線程發送信號,子線程收到了信號開始執行,其線程號爲0X1218,執行結束後發送信號給Controller處理結果。
首先寫MyThread類,該類繼承於QThread,該類中自定義了信號槽和重寫了run函數。頭文件以下:
MyThread.h內容以下
#ifndef MYTHREAD_H #define MYTHREAD_H #include<QThread> #include<QDebug> class MyThread : public QThread { Q_OBJECT public: MyThread(QObject* parent = nullptr); //自定義發送的信號 signals: void myThreadSignal(const int); //自定義槽 public slots: void myThreadSlot(const int); protected: void run() override; }; #endif // MYTHREAD_H 123456789101112131415161718192021
MyThread.cpp內容以下
#include "mythread.h" MyThread::MyThread(QObject *parent) { } void MyThread::run() { qDebug()<<"myThread run() start to execute"; qDebug()<<" current thread ID:"<<QThread::currentThreadId()<<'\n'; //循環一百萬次 int count = 0; for(int i = 0;i!=1000000;++i) { ++count; } // 發送結束信號 emit myThreadSignal(count); exec(); } void MyThread::myThreadSlot(const int val) { qDebug()<<"myThreadSlot() start to execute"; qDebug()<<" current thread ID:"<<QThread::currentThreadId()<<'\n'; // 循環一百萬次 int count = 888; for(int i = 0;i!=1000000;++i) { ++count; } } 12345678910111213141516171819202122232425262728293031323334
在Controller類中實現這MyThread的調用。
Controller.h內容以下
#include "mythread.h" MyThread::MyThread(QObject *parent) { } void MyThread::run() { qDebug()<<"myThread run() start to execute"; qDebug()<<" current thread ID:"<<QThread::currentThreadId()<<'\n'; // 循環一百萬次 int count = 0; for(int i = 0;i!=1000000;++i) { ++count; } // 發送結束信號 emit myThreadSignal(count); exec(); } void MyThread::myThreadSlot(const int val) { qDebug()<<"myThreadSlot() start to execute"; qDebug()<<" current thread ID:"<<QThread::currentThreadId()<<'\n'; // 循環一百萬次 int count = 888; for(int i = 0;i!=1000000;++i) { ++count; } } 12345678910111213141516171819202122232425262728293031323334
Controller.cpp內容以下
#include "controller.h" #include <mythread.h> Controller::Controller(QObject *parent) : QObject(parent) { myThrd = new MyThread; connect(myThrd,&MyThread::myThreadSignal,this,&Controller::handleResults); // 該線程結束時銷燬 connect(myThrd, &QThread::finished, this, &QObject::deleteLater); connect(this,&Controller::operate,myThrd,&MyThread::myThreadSlot); // 啓動該線程 myThrd->start(); QThread::sleep(5); emit operate(999); } Controller::~Controller() { myThrd->quit(); myThrd->wait(); } 1234567891011121314151617181920
main函數的內容和上例中相同,所以就不貼了。
經過自定義一個繼承QThread的類,實例化該類的對象,重載run()函數爲須要作的工做。而後在須要的地方調用start函數來執行run函數中的任務。然而有趣的是,myThread.start()以後我又從主函數觸發了一個信號,對應於子線程的槽,子線程的槽函數中打印當前執行的線程的編號,能夠看到,執行子線程的槽函數的線程編號倒是主線程的編號。
兩種方法來執行線程均可以,隨便你的喜歡。不過看起來第二種更加簡單,容易讓人理解。不過咱們的興趣在於這兩種使用方法到底有什麼區別?其最大的區別在於:
PS:
以上代碼是Qt5.7開發環境,採用的是VS2015的64位編譯器。代碼能夠直接複製粘貼運行