You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt中如何让QThread收到主线程或Worker信号后正确停止?

Qt线程停止实现的问题排查

我在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 06:11:31