You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Qt中创建并行线程?附Worker线程管理类实现代码

嘿,我来帮你捋捋Qt里创建并行线程的正确姿势,顺便看看你写的Worker类怎么优化~

在Qt中创建并行线程的正确方法

Qt里创建并行线程主要有两种常用模式,我一个个给你拆解:

1. Worker对象+QThread模式(官方推荐)

这是Qt官方最推荐的方式——把业务逻辑封装在继承自QObject的Worker类里,再把这个对象移到独立的QThread中运行,和你现在的思路方向一致,但代码细节还有优化空间。

先看标准的Worker类结构

#include <QObject>
#include <QThread>
#include <QDebug>

class Worker : public QObject
{
    Q_OBJECT
public:
    explicit Worker(QObject *parent = nullptr) 
        : QObject(parent), m_isRunning(false) {}
    
    // 注意:耗时操作绝对不能放在构造函数里,要放到槽函数中执行
public slots:
    void startWork() {
        m_isRunning = true;
        // 这里写你的核心业务逻辑,比如调用QProcess、处理文件等
        while(m_isRunning) {
            qDebug() << "Worker running in thread ID:" << QThread::currentThreadId();
            
            // 加个小延时避免CPU被占满,根据你的业务调整
            QThread::msleep(100);
        }
        emit workFinished();
    }

    void stopWork() {
        // 优雅停止线程,不要用强制终止
        m_isRunning = false;
    }

signals:
    void workFinished();
    void errorHappened(const QString &errorMsg);

private:
    // 用QAtomicBool保证多线程下的线程安全,比普通bool更可靠
    QAtomicBool m_isRunning;
};

主线程中如何使用这个Worker

// 比如在MainWindow或者其他主线程对象中初始化
Worker *myWorker = new Worker();
QThread *workerThread = new QThread();

// 连接信号槽,管理线程生命周期
connect(workerThread, &QThread::started, myWorker, &Worker::startWork);
connect(myWorker, &Worker::workFinished, workerThread, &QThread::quit);
// 线程结束后自动释放资源,避免内存泄漏
connect(myWorker, &Worker::workFinished, myWorker, &Worker::deleteLater);
connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);

// 把Worker对象移到子线程中
myWorker->moveToThread(workerThread);

// 启动线程
workerThread->start();

// 当需要停止线程时,调用Worker的stopWork槽即可
// myWorker->stopWork();

针对你写的Worker_Bis类的修正建议

你的代码思路是对的,但有几个细节要调整:

  • 不要在Worker的构造函数里直接new QThread()moveToThread,应该在主线程中创建QThread,再把Worker移过去,这样线程的生命周期管理更清晰。
  • QAtomicBool代替普通的flag_runningflag_stopping,避免多线程下的竞态问题。
  • 尽量用Qt5的新信号槽语法(&类名::信号/槽),比旧的SIGNAL/SLOT宏更安全,编译期就能检查错误。
  • 记得补全未写完的信号槽连接,比如线程结束后要自动释放线程和Worker对象,避免内存泄漏。

2. 继承QThread重写run()方法(不推荐)

这种方式是直接继承QThread,把业务逻辑写在重写的run()方法里,但Qt官方不推荐这么做——因为QThread本质是线程的管理类,不是线程的载体,容易出现对象生命周期混乱的问题。不过还是给你举个例子参考:

#include <QThread>
#include <QDebug>

class MyThread : public QThread
{
    Q_OBJECT
protected:
    void run() override {
        qDebug() << "Thread running with ID:" << currentThreadId();
        // 耗时操作逻辑
        while(!isInterruptionRequested()) {
            // 你的业务代码
            msleep(100);
        }
    }
};

// 使用方式
MyThread *thread = new MyThread();
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
thread->start();

// 停止线程时用优雅的方式
// thread->requestInterruption();
// thread->wait();

关键注意事项

  • 线程安全:绝对不要在子线程中操作UI控件!Qt的UI类只能在主线程(GUI线程)中访问,如果需要更新UI,要通过信号槽把数据传到主线程处理。
  • 资源释放:一定要用deleteLater()确保线程和Worker对象在合适的时机被销毁,避免内存泄漏。
  • 避免强制终止:永远不要用terminate()方法终止线程,这会导致线程资源无法正常释放,要用标志位或者requestInterruption()优雅停止。

内容的提问来源于stack exchange,提问作者Bismarck Gomes

火山引擎 最新活动