QThread finished信号仅在Qt::DirectConnection下打印的原因咨询
代码示例
#define DEBUG qDebug()<<__LINE__<<__FUNCTION__ struct MainWindow::MainWindowImpl { QThread* thread = nullptr; }; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), d(new MainWindowImpl) { d->thread = new QThread(this); connect(d->thread , &QThread::finished , this , [](){ DEBUG << "thread finished " ; } , Qt::DirectConnection); d->thread->start(); } MainWindow::~MainWindow() { d->thread->quit(); d->thread->wait(); delete d->thread; delete d; }
问题
关闭MainWindow时,为何仅在指定Qt::DirectConnection时才会打印“thread finished”,而使用Qt::QueuedConnection则不会?
我理解Qt::DirectConnection会在子线程发出finished信号时立即执行打印;而Qt::QueuedConnection会让MainWindow对象在主线程处理,信号会被放入事件队列末尾,仅当事件循环处理时才会执行。
环境:C++17、Qt 5.15.2、Windows 11、CPU I7 13700、RAM 16G
解答
核心原因在于主线程事件循环的状态和两种连接类型的执行时机差异:
Qt::DirectConnection的执行逻辑
当调用d->thread->quit()后,子线程会退出事件循环并发出finished信号。由于是直接连接,槽函数会立即在发出信号的子线程中执行——此时子线程还未完全终止(wait()是等待线程彻底结束的调用,在quit()之后、wait()完成前,子线程仍处于收尾阶段,能正常执行槽函数),所以打印语句会正常输出。Qt::QueuedConnection的执行逻辑
队列连接会将信号事件放入主线程的事件队列,等待主线程的事件循环取出处理。但此时MainWindow正在执行析构函数,主线程的事件循环已经处于退出/停止处理新事件的状态(窗口关闭时,应用的主事件循环通常会启动终止流程,不再处理队列中的新事件)。因此,finished对应的槽函数事件永远不会被主线程处理,自然不会打印内容。
简单总结:队列连接依赖主线程事件循环,但窗口关闭时主线程已停止处理新事件;直接连接不依赖主线程,在子线程收尾阶段就能执行槽函数。
内容的提问来源于stack exchange,提问作者z Muiskc

