一、怎么用
使用一个QObject作为Worker,并moveToThread到线程上,那么这个QObject生存在此线程上,其信号会在此线程上发射,其槽函数在此线程上执行。
意味着什么,意味着多线程操作时,若通过信号槽方式,则无需关心数据线程安全性,无需加锁解锁。
语言总是晦涩的,直接看以下烂大街的代码吧。
Worker.h
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
~Worker();
public slots:
void doSomething(const QString& cmd);
signals:
void resultNotify(const QString& des);
};
Worker.cpp
Worker::Worker(QObject *parent)
: QObject(parent)
{
qDebug() << "Worker()" << "thread:" << QThread::currentThreadId();
}
Worker::~Worker()
{
qDebug() << "~Worker()" << "thread:" << QThread::currentThreadId();
}
void Worker::doSomething(const QString &cmd)
{
qDebug() << "doSomething()" << cmd << "thread:" << QThread::currentThreadId();
emit resultNotify("doSomething ok!");
}
在Worker中doSomething,干完后,发射结果通知信号。
接下来,把Worker移动到QThread上,并建立信号槽。
Controller.h
class Controller : public QObject
{
Q_OBJECT
public:
Controller(QObject* parent = nullptr);
~Controller();
public slots:
void handleResults(const QString &des);
signals:
void operate(const QString &cmd);
private:
QThread thread;
};
Controller.cpp
Controller::Controller(QObject* parent)
: QObject(parent)
{
Worker *worker = new Worker();
worker->moveToThread(&thread);
connect(&thread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doSomething);
connect(worker, &Worker::resultNotify, this, &Controller::handleResults);
thread.start();
}
Controller::~Controller()
{
thread.quit();
thread.wait();
}
void Controller::handleResults(const QString &des)
{
qDebug() << "handleResults()" << des << "thread:" << QThread::currentThreadId();
}
测试代码
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
qDebug() << "main thread:" << QThread::currentThreadId();
Controller* controller = new Controller(this);
emit controller->operate("copy");
}
运行结果:
可以看到doSomething()执行在次线程上的;
我们关闭窗口时,Worker析构函数也是执行在次线程上的。
二、为什么要这么用
与重写run()方式对比,以及讲解对象归属原理之类的文章很多了,自行百度吧。
我想说的是,这么用的适用场景:
- 适合单次任务执行,即有点像懒人,触发一下,干一次活;
- 适合干完活,需要主动推送一个通知;
- 适合用于简化多线程中,对数据安全的保护。
说完了适用,那么它不适用的场景呢:
- 不适用高频率任务,即跑完一个任务,可能没有时间休息,持续跑。
执行高频率任务,还是需要使用重写QThread::run()的方式,来实现。
若对你有帮助,欢迎点赞、收藏、评论,你的支持就是我的最大动力!!!
同时,阿超为大家准备了丰富的学习资料,欢迎关注公众号“超哥学编程”,即可领取。