目录
QThread
官方解析
Detailed Description
QThread类提供了跨平台的线程管理的API。
QThread对象在程序中管理一个线程。 使用run()来执行,默认情况下run()通过调用exec()实现事件循环,并且run()使得QThread的对象的线程中Qt的事件循环跑起来。
可以用QObject::moveToThread()使worker对象放入线程中。
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
在这个代码里面Worker的槽函数在另外一个线程中执行。但可以使用信号与槽让任意的object对象(继承了QObject,并且带有Q_OBJECT宏)信号连接Worker的槽函数。这种跨线程的信号与槽的连接方式是安全的,这得归功于connect()函数的第五个参数(参考链接)默认调用了queued connections。
另外一种方式让代码运行在其他线程的方式是,子类化QThread类,并且重新实现run()函数,栗子如下:
class WorkerThread : public QThread
{
Q_OBJECT
void run() Q_DECL_OVERRIDE {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &s);
};
void MyObject::startWorkInAThread()
{
WorkerThread *workerThread = new WorkerThread(this);
connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
在这个栗子中,thread将会在函数返回的时候退出。他们将不会在线程中运算事件循环,除非他们调用exec().
要注意QThread实例存在与谁实例化他的线程中,而不是在谁调用了run()这个函数的线程中。这就意味着QThread以队列连接的信号与槽,将会执行在实例化他的线程中,而不是调用run()函数这个线程中。因此如果希望在新线程里面调用槽函数得使用worker对象显示出的方式;不应该将槽函数直接实例在子类化的QThread中。
当子类化QThread类后,构造函数会旧的(实例化他的)那个线程中执行,而run()的执行将会在新线程中。如果这两个函数都访问了成员变量,从两个不同的线程中访问这个变量,要检测这么做是否安全!
Note:要小心,在不同对象或者线程中交互。查看Synchronizing Threads查看详情!
博主栗子
子线程发射信号给主线程
当子线程里面emit一个signal给主线程,这是十分常见的,但主线程emit一个signal给子线程那么会发送些什么呢!
运行截图如下:
源码瑞星啊:
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class QThread;
class Worker;
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
protected:
void timerEvent(QTimerEvent *event)Q_DECL_OVERRIDE;
signals:
void hello();
void sendMsg();
private:
QThread *thread[3];
Worker *worker[3];
};
#endif // WIDGET_H
worker.h
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
class Worker : public QObject
{
Q_OBJECT
public:
Worker(QObject *parent = 0);
public slots:
void beginToWork();
void mainThreadMsg();
};
#endif // WORKER_H
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.cpp
#include "widget.h"
#include "worker.h"
#include <QDebug>
#include <QThread>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
for(int i=0;i<3;i++){
thread[i]=new QThread;
worker[i]=new Worker;
worker[i]->moveToThread(thread[i]);
connect(thread[i],&QThread::finished,worker[i],&QObject::deleteLater);
connect(this,&Widget::hello,worker[i],&Worker::beginToWork);
connect(this,SIGNAL(sendMsg()),worker[i],SLOT(mainThreadMsg()));
thread[i]->start();
}
emit hello();
startTimer(1000);
}
Widget::~Widget()
{
for(int i=0;i<3;i++){
thread[i]->quit();
thread[i]->wait();
delete thread[i];
delete worker[i];
}
}
void Widget::timerEvent(QTimerEvent *event)
{
Q_UNUSED(event)
emit sendMsg();
// for(int i=0;i<3;i++){
// qDebug()<<"main thread, worker "<<i;
// worker[i]->mainThreadMsg();
// }
}
worker.cpp
#include "worker.h"
#include <QDebug>
#include <QThread>
Worker::Worker(QObject *parent) : QObject(parent)
{
}
void Worker::beginToWork()
{
while(true){
QThread::sleep(2);
qDebug()<<QThread::currentThreadId()<<" beginToWork";
mainThreadMsg();
}
}
void Worker::mainThreadMsg()
{
qDebug()<<"mainThreadMsg called!"<<QThread::currentThreadId();
}