官方鏈接QThread Class | Qt Core 5.15.14
使用QThread::run()
簡單來說就是繼承QThread類,并重寫run()函數(shù),這樣run()函數(shù)中的代碼就會運行在子線程中。
QThread對象管理著一個線程,并通過start函數(shù)啟動這個線程,線程要執(zhí)行的代碼都在run()里面,run()函數(shù)的進入和返回,就相當于子線程的啟動和結束。
但是run()函數(shù)何時返回呢?一般有三種情況:
- run中代碼走一遍就返回了。
- run中有while循環(huán),在循環(huán)中有退出循環(huán)的flag變量,由外部程序置位這個flag,使循環(huán)退出,從而返回。
- run中最后一行是事件循環(huán)exec(),即程序會卡在這一行:this->exec();這種情況需要調(diào)用exit()或者terminate()才能讓事件循環(huán)停下,從而讓run返回。
當run函數(shù)執(zhí)行完畢的時候,新線程也就結束了,并且發(fā)出finished()信號。
#ifndef SOMETHINGTHREAD_H
#define SOMETHINGTHREAD_H
#include <QThread>
#include <QObject>
class SomethingThread : public QThread
{
Q_OBJECT
public:
explicit SomethingThread(QObject *parent = nullptr);
void run() override;//線程函數(shù)
private: signals:
void resultReady(const QString result);//如果有線程計算結果返回,可以通過這種方式
};
#endif // SOMETHINGTHREAD_H
#include "somethingthread.h"
#include "qdebug.h"
SomethingThread::SomethingThread(QObject *parent)
: QThread{parent}
{
}
void SomethingThread::run()
{
for(int i=0;i<10;i++)
{
qDebug()<<"doing something %d"<<i<<" thread_id"<<QThread::currentThreadId();
QThread::sleep(1);
}
emit this->resultReady("finish");//觸發(fā)信號,傳遞結果參數(shù)
}
SomethingThread* sth=new SomethingThread(this);
connect(sth,&SomethingThread::resultReady,this,&SIHToolBar::onResultReady);//使用接收結果
connect(sth,&SomethingThread::finished,sth,&QObject::deleteLater);
sth->start();
void SIHToolBar::onResultReady(const QString result)
{
qDebug()<<"onResultReady result="<<result<<" thread_id="<<QThread::currentThreadId();
}
doing something %d 0 thread_id 0x6188
doing something %d 1 thread_id 0x6188
doing something %d 2 thread_id 0x6188
doing something %d 3 thread_id 0x6188
doing something %d 4 thread_id 0x6188
doing something %d 5 thread_id 0x6188
doing something %d 6 thread_id 0x6188
doing something %d 7 thread_id 0x6188
doing something %d 8 thread_id 0x6188
doing something %d 9 thread_id 0x6188
onResultReady result= "finish" thread_id= 0x2f0
有幾點需要注意:
- QThread類中的run()函數(shù)默認實現(xiàn)是這樣的
QThread::run() { this->exec(); }
,也就是默認開啟了事件循環(huán)。 - 只有run函數(shù)中的代碼段是在子線程中執(zhí)行的。如果run中使用了成員變量,而且其他地方也使用到了它,這時需要自行檢查是否線程安全。
- run函數(shù)中發(fā)射的信號,連接了使用它的對象的槽函數(shù),實際上是跨線程了的。
- 官方不推薦使用這種方式
使用QObject::moveToThread()
moveToThread 方法,是把我們需要的工作全部封裝在一個類中,將每個任務定義為一個槽函數(shù),再建立觸發(fā)這些槽函數(shù)的信號,然后連接信號和槽,最后調(diào)用 moveToThread 方法將這個類交給一個 QThread 對象,再調(diào)用 QThread 的 start() 函數(shù)使其全權處理事件循環(huán)。于是,任何時候我們需要讓子線程執(zhí)行某個任務,只需要發(fā)出對應的信號就可以。文章來源:http://www.zghlxwxcb.cn/news/detail-475313.html
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
signals:
void resultReady(const QString& result);//線程完成工作時發(fā)送的信號
public slots:
void doWork(const QString& param);//定義了線程要執(zhí)行的操作
};
#endif // WORKER_H
#include "worker.h"
#include <QDebug>
#include <QThread>
Worker::Worker(QObject *parent)
: QObject{parent}
{
}
void Worker::doWork(const QString ¶m)
{
for(int i=0;i<10;i++)
{
qDebug()<<"doWork %d"<<i<<" thread_id"<<QThread::currentThreadId();
QThread::sleep(1);
}
emit this->resultReady("finish");//觸發(fā)信號,傳遞結果參數(shù)
}
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <QObject>
#include <QThread>
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
explicit Controller(QObject *parent = nullptr);
~Controller();
signals:
void doWork(const QString& param);//發(fā)送信號 觸發(fā)線程
public slots:
void onResultReady(const QString& result);//處理子線程執(zhí)行的結果
};
#endif // CONTROLLER_H
#include "controller.h"
#include "worker.h"
#include <QDebug>
Controller::Controller(QObject *parent)
: QObject{parent}
{
Worker* work=new Worker();
work->moveToThread(&this->workerThread);//調(diào)用moveToThread將該任務交給
connect(&this->workerThread,&QThread::finished,work,&QObject::deleteLater);//當線程結束的時候,銷毀worker對象
connect(this,&Controller::doWork,work,&Worker::doWork);//通過controller的dowork信號 連接 worker對象的doworker槽函數(shù)
connect(work,&Worker::resultReady,this,&Controller::onResultReady);
workerThread.start();
qDebug()<<"main thread_id="<<QThread::currentThreadId();
emit this->doWork("start");
//work->doWork("start");//這種直接調(diào)用的方式?jīng)]有在子線程中執(zhí)行
}
Controller::~Controller()
{
workerThread.quit();
workerThread.wait();
}
void Controller::onResultReady(const QString &result)
{
qDebug()<<"onResultReady result="<<result<<" thread_id="<<QThread::currentThreadId();
}
main thread_id= 0x7254
doWork %d 0 thread_id 0x5970
doWork %d 1 thread_id 0x5970
doWork %d 2 thread_id 0x5970
doWork %d 3 thread_id 0x5970
doWork %d 4 thread_id 0x5970
doWork %d 5 thread_id 0x5970
doWork %d 6 thread_id 0x5970
doWork %d 7 thread_id 0x5970
doWork %d 8 thread_id 0x5970
doWork %d 9 thread_id 0x5970
onResultReady result= "finish" thread_id= 0x7254
有幾點需要注意:文章來源地址http://www.zghlxwxcb.cn/news/detail-475313.html
- 任何對象只要執(zhí)行了moveToThread,那么該對象的所有槽函數(shù)就會在子線程執(zhí)行(前提是,該槽函數(shù)是被信號觸發(fā)的),如果直接顯示調(diào)用這些槽函數(shù),仍然會運行在原線程,不會出現(xiàn)多線程的效果。
- 我們可以在一個worker類中定義多個需要做的工作(槽函數(shù)),然后觸發(fā)信號,子線程就可以執(zhí)行。
到了這里,關于【Qt】多線程QThread::run()與QObject::moveToThread()的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!