Qt中如何让QThread收到主线程或Worker信号后正确停止?
我在Qt应用中有两个线程:主线程和myThread。我希望myThread在收到对应Worker类的workFinished信号,或是主线程的stopMyThread信号时停止。
我的实现代码如下:
MyClass中的线程创建代码
void MyClass::myFunction() { //DO SOME STUFF... myThread = new QThread(this); //myThread 和 myThreadWorker 的声明在.h文件中 myThreadWorker = new Worker(this); if (!myThread->isRunning()) { connect(myThread, &QThread::started, myThreadController, &Worker::doWork); connect(myThreadController, &Worker::workFinished, myThread, &QThread::quit); connect(this, &MyClass::stopMyThread, myThread, &QThread::quit); connect(myThreadController, &Worker::workFinished, myThreadController, &Worker::deleteLater); connect(this, &MyClass::stopMyThread, myThreadController, &Worker::deleteLater); connect(myThread, &QThread::finished, myThread, &QThread::deleteLater); myThreadWorker -> moveToThread(myThread); myThread -> start(); } }
Worker类的doWork实现
void Worker::doWork() { while (buffer > 0) { buffer -= 5; //DO SOME STUFF } emit workFinished(); }
请问这种实现方式是否正确?会引发哪些问题?我的应用在通过主线程信号停止myThread时发生崩溃。
这种实现存在多个问题,正是这些问题导致了崩溃:
1. 变量名混乱导致空指针访问
代码中创建的是myThreadWorker = new Worker(this);,但后续信号连接用的是myThreadController,这会直接触发空指针调用,是崩溃的直接原因之一,必须统一变量名。
2. Worker父类设置违反Qt线程规则
创建Worker时传入主线程对象this作为父类,之后又调用myThreadWorker->moveToThread(myThread);。Qt要求对象的父类必须和对象处于同一线程,否则会导致线程上下文混乱,触发未定义行为。正确做法是创建Worker时不要设置父类。
3. 阻塞式循环无法响应停止信号
doWork里的while是阻塞式循环,不会处理线程事件。主线程发出stopMyThread信号触发QThread::quit()时,线程事件循环被标记为退出,但doWork仍在运行;此时触发deleteLater销毁Worker,会导致对象在执行代码时被析构,直接引发崩溃。
4. 销毁顺序存在风险
当前逻辑中,workFinished和stopMyThread信号会直接触发Worker的deleteLater,但此时线程可能还在运行,Worker的析构和线程运行过程冲突,引发内存错误。
正确的实现方式
第一步:修改Worker类,添加可中断标志
给Worker添加原子布尔变量,让循环可以响应停止请求:
#include <QObject> #include <atomic> class Worker : public QObject { Q_OBJECT public: explicit Worker(QObject *parent = nullptr) : QObject(parent), m_stop(false) {} void stop() { m_stop.store(true); } signals: void workFinished(); public slots: void doWork() { while (buffer > 0 && !m_stop.load()) { buffer -= 5; //DO SOME STUFF // 若循环耗时较长,可添加QThread::msleep(1)让线程有机会处理事件 } emit workFinished(); } private: std::atomic<bool> m_stop; int buffer; // 假设buffer是类成员变量 };
第二步:修正MyClass中的线程逻辑
void MyClass::myFunction() { //DO SOME STUFF... // 确保myThread和myThreadWorker是类成员,初始为nullptr if (myThread == nullptr || !myThread->isRunning()) { myThread = new QThread(this); // 创建Worker时不设置父类 myThreadWorker = new Worker(); // 线程启动后执行doWork connect(myThread, &QThread::started, myThreadWorker, &Worker::doWork); // Worker完成后退出线程 connect(myThreadWorker, &Worker::workFinished, myThread, &QThread::quit); // 线程结束后销毁自身和Worker connect(myThread, &QThread::finished, myThread, &QThread::deleteLater); connect(myThread, &QThread::finished, myThreadWorker, &Worker::deleteLater); // 停止信号先通知Worker中断循环,再退出线程 connect(this, &MyClass::stopMyThread, myThreadWorker, &Worker::stop); connect(this, &MyClass::stopMyThread, myThread, &QThread::quit); myThreadWorker->moveToThread(myThread); myThread->start(); } }
关键改进点
- 用原子变量
m_stop让Worker循环可以响应停止请求,避免阻塞线程事件循环 - 统一变量名,消除空指针风险
- 移除Worker的父类设置,保证线程上下文正确
- 调整销毁顺序:线程结束后再销毁Worker,避免对象运行时被析构
- 停止信号先通知Worker中断循环,再退出线程,确保Worker安全结束
内容的提问来源于stack exchange,提问作者Adrian Suliga

