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位编译器。代码能够直接复制粘贴运行