QThread *ptr=new QThread();
Worker *pwk=new Worker();
ptr->setObjectName("Worker thread");
pwk->moveToThread(ptr);
QObject::connect(ptr,&QThread::started,pwk,&Worker::run);
QObject::connect(pwk,&Worker::finished,ptr,[ptr](){
qInfo()<<"get finished signal to quit";
ptr->quit();});
ptr->start();
if(!ptr->wait(5000))
{
qInfo()<<ptr<<"is still running:"<<ptr->isRunning();
}
qInfo()<<"exit from"<<Q_FUNC_INFO;
Worker是自定义的QObject子类,它有signal finished。上面的代码在main thread中运行,发现ptr的started signal可以传递给pwk的run函数,但是在ptr->wait(5000)的5秒钟内,pwk的finished signal不能传给ptr.
后来偶然发现增加connection type设定:
QObject::connect(pwk,&Worker::finished,ptr,[ptr](){
qInfo()<<"get finished signal to quit";
ptr->quit();},Qt::DirectConnection);
解决了该问题。后面查找资料,发现原因在于connection type如果没有明确在connect中指定,则缺省为autoconnection。那么Qt如果检测到signal发射方和接收方是在同一个thread,就会使用DirectConnection,如果不是,就会使用QueuedConnection。这里面pwk被move到ptr中,所以它的thread affinity,即pwk->thread()的返回是ptr。但是这不表明pwk和ptr是在一个thread中。ptr因为在main thread中创建,所以ptr->thread()返回是main thread. 因此,如不指定connection type, Qt将采用QueuedConnection,即把signal发到main thread的event loop中。而此时main thread被block在 ptr->wait(5000)中,因此event loop无法接收到该信号。只有当从wait中返回,main thread才能进入event loop循环,接收signal并调用ptr->quit()。
总结一下:
1. connect函数里,如果不指定connection type,默认为autoconnection,如果发射方和接收方在一个thread里,则采用DirectConnection, 即直接调用接收方的函数。而如果不在一个thread里,则发送信号给接收thread的event loop,由它来处理调用接收方的函数。
2. 是否在一个thread里取决于该object的thread affinity,即thread()返回值。一般而言,一个QObject在哪个线程创建,它的affinity就是这个线程,除非调用moveToThread函数把其调到另一个线程,这种情况下,它的thread affinity就变成了函数中的参数。