前言
官方关于QThread的用法有两种:一是子类QThread,并重新实现run;二是使用QObject::MoveToThread,通过信号槽在不同的线程内通信。
最近看到了一种写法,就是将两者融合就是子类QThread,然后this->moveToThread(this)。觉得很奇怪,但是也不能说有错,自己写demo测了一下,能用,就是需要注意的东西挺多。
说明
尝试了几种情况,不同情况,需要注意的东西不一样。
不重新实现run
只是子类QThread(假如类名为MyThread),不重新实现run,在构造函数或者其他地方进行moveToThread。这种情况,使用信号槽的QueueConnection进行连接,MyThread里的槽函数是在子线程中执行的。
//----------------------------.h文件----------------------------
#include<QThread>
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = Q_NULLPTR);
~ MyThread() ;
public slots:
void sayHello();
};
//----------------------------.cpp文件----------------------------
MyThread::MyThread(QObject *parent)
:QThread(parent)
{
this->moveToThread(this);
}
void MyThread::sayHello()
{
qDebug()<<__FUNCDNAME__<<QThread::currentThreadId();
}
在主界面调用
connect(ui->pushButton,SIGNAL(clicked(bool)),this,SIGNAL(say()));
connect(this,SIGNAL(say()),&m_thread,SLOT(sayHello()),Qt::QueuedConnection);
m_thread.start();
点击按钮,可看到打印如下
结论:通过以上实践,可以看到此方式是可行的,主线程发送信号,在子线程中执行。
分析:不实现run,也就是说QThread::start() 的时候调用的是QThread本身的run,也就是在子线程启动了事件循环,两线程通过信号槽通信,这没毛病。
QThreads begin executing in run(). By default, run() starts the event loop by calling exec() and runs a Qt event loop inside the thread
重新实现run
调用exec()
重新实现run,并且在run里调用exec(),此使用跟上面的几乎一样,只是可以在调用exec()前,执行一些代码,当然执行的代码也是子线程中执行的。
void MyThread::run()
{
qDebug()<< "Entering thread";
{
//to do something
sayHello();
// Start the event loop.
qDebug() << "Event loop starting";
exec();
qDebug() << "Event loop stopped";
}
qDebug() << "Exiting thread";
}
看打印,可以看出整个执行流程:
结论:可行!
不调用exec()
不执行exec(),即在子线程中不启动事件循环。
void MyThread::run()
{
sayHello();
}
结果:信号槽不可行的,除非将连接方式改为直连Qt::DirectConnection,也就是在主线程或者其他线程中执行槽函数。
结论:此种使用方法,只有run函数的在子线程中执行,即使使用this->moveToThread(this),也是不能通过信号槽的方式,让此类中的其他函数在子线程中执行,同理,QMetaObject::invokeMethod使用队列连接方式的也不行,也就是只要依赖子线程里的事件循环的都不行。
注意:在run外定义的QTimer是无法是在run里启动的。