Qt中调用QThread的wait()为何会阻止线程接收信号?
问题分析与解答
代码片段
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;
核心原因
问题由两个关键机制共同导致:
- QThread实例
ptr在主线程创建,它的线程亲和性属于主线程。所有发送给ptr的信号、需要执行的槽函数,都必须依赖主线程的事件循环调度才能执行。 ptr->wait(5000)会直接阻塞调用它的主线程,主线程阻塞期间完全停止处理任何事件(包括事件队列中的信号投递)。即使Worker::finished信号已在子线程触发,连接到ptr的lambda槽函数因需在主线程执行,只能暂存在主线程事件队列中,直到wait返回、主线程恢复事件循环后才会被执行,进而调用ptr->quit()。
补充说明:你提到Worker::finished连接的其他pwk槽函数能正常执行,是因为这些槽的接收者是pwk,而pwk已被moveToThread转移到子线程,信号会直接在子线程触发槽函数,无需经过主线程事件循环。
解决方案
如果需要等待子线程完成且及时响应信号,建议避免用wait()阻塞主线程,改用事件循环实现等待:
ptr->start(); QEventLoop loop; QObject::connect(ptr, &QThread::finished, &loop, &QEventLoop::quit); // 启动事件循环,最多等待5秒 loop.exec(QEventLoop::ExcludeUserInputEvents, 5000); if (ptr->isRunning()) { qInfo()<<ptr<<"is still running:"<<ptr->isRunning(); ptr->quit(); ptr->wait(); } qInfo()<<"exit from"<<Q_FUNC_INFO;
或完全依赖信号处理后续逻辑,避免主动等待:
ptr->start(); QObject::connect(ptr, &QThread::finished, [ptr](){ qInfo()<<"thread finished"; ptr->deleteLater(); });
内容的提问来源于stack exchange,提问作者li_jessen
相关产品推荐
相关产品推荐

