一、怎么用
使用一个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()的方式,来实现。
若对你有帮助,欢迎点赞、收藏、评论,你的支持就是我的最大动力!!!
同时,阿超为大家准备了丰富的学习资料,欢迎关注公众号“超哥学编程”,即可领取。