官方链接QThread Class | Qt Core 5.15.14
使用QThread::run()
简单来说就是继承QThread类,并重写run()函数,这样run()函数中的代码就会运行在子线程中。
QThread对象管理着一个线程,并通过start函数启动这个线程,线程要执行的代码都在run()里面,run()函数的进入和返回,就相当于子线程的启动和结束。
但是run()函数何时返回呢?一般有三种情况:
- run中代码走一遍就返回了。
- run中有while循环,在循环中有退出循环的flag变量,由外部程序置位这个flag,使循环退出,从而返回。
- run中最后一行是事件循环exec(),即程序会卡在这一行:this->exec();这种情况需要调用exit()或者terminate()才能让事件循环停下,从而让run返回。
当run函数执行完毕的时候,新线程也就结束了,并且发出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;//线程函数
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");//触发信号,传递结果参数
}
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()函数默认实现是这样的
QThread::run() { this->exec(); }
,也就是默认开启了事件循环。 - 只有run函数中的代码段是在子线程中执行的。如果run中使用了成员变量,而且其他地方也使用到了它,这时需要自行检查是否线程安全。
- run函数中发射的信号,连接了使用它的对象的槽函数,实际上是跨线程了的。
- 官方不推荐使用这种方式
使用QObject::moveToThread()
moveToThread 方法,是把我们需要的工作全部封装在一个类中,将每个任务定义为一个槽函数,再建立触发这些槽函数的信号,然后连接信号和槽,最后调用 moveToThread 方法将这个类交给一个 QThread 对象,再调用 QThread 的 start() 函数使其全权处理事件循环。于是,任何时候我们需要让子线程执行某个任务,只需要发出对应的信号就可以。文章来源:https://www.toymoban.com/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);//线程完成工作时发送的信号
public slots:
void doWork(const QString& param);//定义了线程要执行的操作
};
#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");//触发信号,传递结果参数
}
#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);//发送信号 触发线程
public slots:
void onResultReady(const QString& result);//处理子线程执行的结果
};
#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);//调用moveToThread将该任务交给
connect(&this->workerThread,&QThread::finished,work,&QObject::deleteLater);//当线程结束的时候,销毁worker对象
connect(this,&Controller::doWork,work,&Worker::doWork);//通过controller的dowork信号 连接 worker对象的doworker槽函数
connect(work,&Worker::resultReady,this,&Controller::onResultReady);
workerThread.start();
qDebug()<<"main thread_id="<<QThread::currentThreadId();
emit this->doWork("start");
//work->doWork("start");//这种直接调用的方式没有在子线程中执行
}
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
有几点需要注意:文章来源地址https://www.toymoban.com/news/detail-475313.html
- 任何对象只要执行了moveToThread,那么该对象的所有槽函数就会在子线程执行(前提是,该槽函数是被信号触发的),如果直接显示调用这些槽函数,仍然会运行在原线程,不会出现多线程的效果。
- 我们可以在一个worker类中定义多个需要做的工作(槽函数),然后触发信号,子线程就可以执行。
到了这里,关于【Qt】多线程QThread::run()与QObject::moveToThread()的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!