Qt多线程

张开发
2026/4/12 1:59:10 15 分钟阅读

分享文章

Qt多线程
一.Qt多线程的四种实现方式1.继承自QThread并重写run函数。2.创建线程和线程对象moveToThread法。3.继承QRunnable并重写run函数通过QThreadPool::start启用。4.QtConcurrent::run(void)适合简单的异步任务且无需管理线程的生命周期。本文主要讲解前两种方式二.继承QThread并重写 run()传统方式class MyThread : public QThread { protected: void run() override { // 这个方法在新线程中执行 qDebug() 线程开始ID: QThread::currentThreadId(); // 执行耗时任务 for (int i 0; i 5; i) { qDebug() 执行任务 i; QThread::msleep(500); // 模拟耗时操作 } qDebug() 线程结束; } }; // 使用 MyThread *thread new MyThread(); // 手动管理线程对象 thread-start(); // 自动调用 run() thread-wait(); // 等待结束 thread-deleteLater(); // 清理三.moveToThread推荐方式注意工作对象必须继承自QObject类才有moveToThread方法。class Worker : public QObject { Q_OBJECT public: Worker() {} public slots: void doWork() { qDebug() 工作开始线程ID: QThread::currentThreadId(); for (int i 0; i 5; i) { emit progress(i); QThread::msleep(300); } emit finished(); } void stop() { qDebug() 停止工作; emit stopped(); } signals: void progress(int value); void finished(); void stopped(); }; // 使用 QThread *thread new QThread(); Worker *worker new Worker(); // 将 worker 移动到新线程 worker-moveToThread(thread); // 连接信号槽自动管理线程对象 connect(thread, QThread::started, this,[worker](){ QTimer::singleShot(0, worker, Worker::doWork); }); connect(worker, Worker::finished, thread, QThread::quit); connect(worker, Worker::finished, worker, Worker::deleteLater); connect(thread, QThread::finished, thread, QThread::deleteLater); // 启动线程 thread-start();该方法线程管理的最佳实践step1创建工作对象Worker 和 线程对象QThreadstep2: Worker-moveToThreadQThreadstep3连接信号槽a.QTimer::singleShot(0,worker,Worker::doWork)或自定义任务信号更推荐外部触发开始信号这样支持多次触发——》通知Worker开始执行任务如定时器开始b.Worker执行完任务信号或外部如UI主线程发出任务停止信号——》通知QThread退出调用quitc.QThread退出信号——》通知Worker清理内部资源可选如停止定时器,或清理堆内存——》清理Worker指针deleteLater——》清理QThread自身指针deleteLaterstep4QThread调用start()进入事件循环同时会发出started 信号可选检查线程状态避免重复启动注意事项1.不推荐适用QThread的started信号直接连接工作对象的任务槽函数。因为QThread::start这一步会先启用操作系统层面的线程然后执行内置run()函数先初始化线程上下文然后发出started信号再调用exec启用线程事件循环最后清理线程上下文但如果工作任务执行极快在exec调用之前就执行完毕了这个过程中发出的信号连接的槽函数会被封装成事件暂存到事件队列等待事件循环工作线程的finished信号触发线程的quit会即时置位线程的退出标记 1即时生效同时把执行quit槽封装成事件存入队列执行槽函数才依赖事件循环后续exec函数开始执行后检测到标记1就直接返回导致事件循环无法启动再间接导致线程退出。QTimer::singleShot 不绑定调用线程事件最终会投递到接收者对象receiver所在的线程 的事件循环中当事件循环运作起来后这个事件才会开始执行。2.必须保证Worker无父对象不然moveToThread会自动失效对象仍会停留在创建它的线程中。3.QThread对象也建议设为无父对象通过deleteLater自动释放不借助Qt父子对象机制。方法1方法2对比对比项继承QThread并重写 run()moveToThread信号槽默认不支持说明信号槽依赖事件循环只能调用exec让线程进入事件循环才能使用信号与槽。支持因为工作对象移入线程对象中执行这个线程对象没有重写run调用start时会默认开启事件循环对象管理❌ 需要手动✅ 自动管理在外部通过信号槽线程对象退出后通知工作对象退出适用场景简单线程复杂多任务四.QThread核心方法1.线程控制// 启动线程 thread-start(); // 启动线程调用 run() // 退出事件循环如果有 thread-quit(); // 正常退出退出码 0 thread-exit(0); // 指定退出码 // 强制终止危险 thread-terminate(); // ⚠️ 不推荐可能导致资源泄漏 // 等待线程结束 thread-wait(); // 阻塞等待 thread-wait(5000); // 带超时等待毫秒2.状态查询// 查询状态 if (thread-isRunning()) { qDebug() 线程正在运行; } if (thread-isFinished()) { qDebug() 线程已结束; } // 获取线程ID Qt::HANDLE threadId thread-currentThreadId(); // 设置优先级 thread-setPriority(QThread::HighPriority); thread-setPriority(QThread::LowPriority); // 优先级常量 QThread::IdlePriority // 最低 QThread::LowestPriority QThread::LowPriority QThread::NormalPriority // 默认 QThread::HighPriority QThread::HighestPriority QThread::TimeCriticalPriority // 最高 QThread::InheritPriority // 继承线程事件循环// ❌ 没有 exec() void run() override { qDebug() 开始; doWork(); // 执行一次 qDebug() 结束; } // ← 线程立即退出 // ✅ 有 exec() void run() override { qDebug() 开始; // 定时器 QTimer *timer new QTimer(); connect(timer, QTimer::timeout, this, MyClass::doWork); timer-start(1000); exec(); // ← 阻塞事件循环运行 timer-deleteLater(); qDebug() 结束; }五.跨线程通信1.信号槽跨线程// Worker.h class Worker : public QObject { Q_OBJECT public slots: void processData(const QByteArray data) { // 处理数据工作线程中执行 QString result data.toBase64(); emit resultReady(result); // 发送结果线程安全 } signals: void resultReady(const QString result); void errorOccurred(const QString message); }; // 使用 Worker *worker new Worker(); QThread *thread new QThread(); worker-moveToThread(thread); // 连接信号槽自动处理跨线程 connect(senderObj, Sender::dataReady, worker, Worker::processData, Qt::QueuedConnection); // 队列连接 connect(worker, Worker::resultReady, this, MyClass::handleResult, Qt::AutoConnection); // 自动选择 thread-start();connect连接类型连接类型说明使用场景Qt::AutoConnection自动选择默认一般情况Qt::DirectConnection同步调用同一线程Qt::QueuedConnection异步调用不同线程Qt::BlockingQueuedConnection阻塞等待需要同步的跨线程2.使用 QMetaObject::invokeMethod// 异步调用类似信号槽 QMetaObject::invokeMethod(worker, processData, Qt::QueuedConnection, Q_ARG(QByteArray, data)); // 同步调用阻塞等待结果 QString result; QMetaObject::invokeMethod(worker, getResult, Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, result));六、实际应用示例示例1网络请求线程class NetworkWorker : public QObject { Q_OBJECT public: NetworkWorker() { m_manager new QNetworkAccessManager(this); } public slots: void fetch(const QUrl url) { QNetworkRequest request(url); QNetworkReply *reply m_manager-get(request); connect(reply, QNetworkReply::finished, [this, reply]() { if (reply-error() QNetworkReply::NoError) { emit success(reply-readAll()); } else { emit error(reply-errorString()); } reply-deleteLater(); }); } signals: void success(const QByteArray data); void error(const QString message); private: QNetworkAccessManager *m_manager; }; // 使用 NetworkWorker *worker new NetworkWorker(); QThread *thread new QThread(); worker-moveToThread(thread); connect(thread, QThread::started, worker, [worker](){ // 线程启动后的初始化 }); connect(worker, NetworkWorker::success, this, MyClass::onSuccess); connect(worker, NetworkWorker::error, this, MyClass::onError); thread-start(); // 发送请求 worker-fetch(QUrl(https://api.example.com/data));示例2定时心跳线程class HeartbeatThread : public QThread { Q_OBJECT public: HeartbeatThread(QObject *parent nullptr) : QThread(parent) {} void stop() { quit(); wait(); } signals: void heartbeat(); void statusChanged(bool online); protected: void run() override { QTimer *timer new QTimer(); connect(timer, QTimer::timeout, this, HeartbeatThread::sendHeartbeat); timer-start(5000); // 5秒心跳 exec(); // 事件循环 timer-deleteLater(); } private slots: void sendHeartbeat() { bool online checkServerStatus(); emit statusChanged(online); emit heartbeat(); } bool checkServerStatus() { // 检查服务器状态 return true; } }; // 使用 HeartbeatThread *heartbeat new HeartbeatThread(); connect(heartbeat, HeartbeatThread::heartbeat, [](){ qDebug() 心跳; }); // 启动 heartbeat-start(); // 停止 heartbeat-stop();示例3文件处理线程class FileProcessor : public QObject { Q_OBJECT public: FileProcessor() {} public slots: void processFiles(const QStringList files) { int total files.size(); int current 0; for (const QString file : files) { if (m_cancelled) break; QByteArray content readFile(file); processContent(content); emit progress(current * 100 / total); } emit completed(m_cancelled ? -1 : total); } void cancel() { m_cancelled true; } signals: void progress(int percent); void completed(int processed); void error(const QString message); private: bool m_cancelled false; QByteArray readFile(const QString path) { QFile file(path); if (!file.open(QIODevice::ReadOnly)) { emit error(file.errorString()); return QByteArray(); } return file.readAll(); } void processContent(const QByteArray ) { // 处理内容 QThread::msleep(100); } }; // 使用 FileProcessor *processor new FileProcessor(); QThread *thread new QThread(); processor-moveToThread(thread); connect(thread, QThread::started, processor, [processor](){ processor-processFiles({file1.txt, file2.txt, file3.txt}); }); connect(processor, FileProcessor::progress, this, MyClass::updateProgress); connect(processor, FileProcessor::completed, this, MyClass::onCompleted); thread-start(); // 取消 processor-cancel();七、生命周期管理1.正确清理class ManagedThread : public QThread { protected: void run() override { // 工作代码 exec(); } }; // 使用并清理 ManagedThread *thread new ManagedThread(); thread-start(); // 停止并清理 void stopThread() { if (thread-isRunning()) { thread-quit(); // 退出事件循环 thread-wait(); // 等待结束 } thread-deleteLater(); // 延迟删除 thread nullptr; }2.自动清理模式// 方式1finished 信号连接 deleteLater connect(thread, QThread::finished, thread, QThread::deleteLater); // 方式2使用作用域 { QThread thread; Worker worker; worker.moveToThread(thread); thread.start(); // ... } // 自动清理 // 方式3使用智能指针 QScopedPointerQThread thread(new QThread()); // 自动删除八、最佳实践1.✅ 推荐做法// 1. 使用 moveToThread 方式 Worker *worker new Worker(); QThread *thread new QThread(); worker-moveToThread(thread); // 2. 使用信号槽通信 connect(thread, QThread::started, worker, Worker::doWork); connect(worker, Worker::finished, thread, QThread::quit); // 3. 正确清理 connect(worker, Worker::finished, worker, Worker::deleteLater); connect(thread, QThread::finished, thread, QThread::deleteLater); // 4. 启动 thread-start(); // 5. 停止 void stop() { emit stopWorker(); // 通知 worker 停止 thread-quit(); thread-wait(); }2.❌ 避免的做法// ❌ 避免在 run() 中直接使用耗时循环 void run() override { while (running) { // 这会阻塞事件循环 doHeavyWork(); } } // ❌ 避免强制终止线程 thread-terminate(); // 可能导致资源泄漏 // ❌ 避免在析构函数中等待线程 ~MyClass() { thread-wait(); // 可能死锁 } // ❌ 避免跨线程直接访问对象 otherThread-object-setValue(100); // 不安全九、常见问题问题1定时器不触发// ❌ 错误 void run() override { QTimer timer; timer.start(1000); // 没有事件循环定时器不会触发 } // ✅ 正确 void run() override { QTimer timer; connect(timer, QTimer::timeout, [](){ /* 处理 */ }); timer.start(1000); exec(); // 事件循环 }问题2线程无法退出// ❌ 错误 void run() override { exec(); // 无法退出 } // ✅ 正确提供退出机制 void run() override { QTimer *timer new QTimer(); connect(timer, QTimer::timeout, [this, timer](){ if (shouldStop) { timer-deleteLater(); quit(); // 退出事件循环 } }); timer-start(100); exec(); }问题3内存访问冲突// ❌ 错误多线程访问共享数据 QListint sharedList; void run() override { exec(); } // 另一个线程 sharedList.append(100); // 竞争条件 // ✅ 正确使用互斥锁 QMutex mutex; QListint sharedList; void safeAppend() { QMutexLocker locker(mutex); sharedList.append(100); }十、完整模板// Worker.h #pragma once #include QObject #include QTimer #include QThread #include QDebug class Worker : public QObject { Q_OBJECT public: explicit Worker(QObject *parent nullptr) : QObject(parent) { m_timer new QTimer(this); connect(m_timer, QTimer::timeout, this, Worker::doWork); } ~Worker() { stop(); } void start(int interval 1000) { m_timer-start(interval); } void stop() { if (m_timer-isActive()) { m_timer-stop(); } } signals: void workDone(const QString result); void progress(int percent); void finished(); private slots: void doWork() { static int count 0; emit progress(count % 100); QString result process(); emit workDone(result); if (count 100) { emit finished(); } } QString process() { // 模拟工作 QThread::msleep(100); return QString(Result-%1).arg(count); } private: QTimer *m_timer; }; // 使用 int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QThread *thread new QThread(); Worker *worker new Worker(); worker-moveToThread(thread); connect(thread, QThread::started, worker, [worker](){ worker-start(); }); connect(worker, Worker::workDone, [](const QString result){ qDebug() 完成: result; }); connect(worker, Worker::finished, thread, QThread::quit); connect(worker, Worker::finished, worker, Worker::deleteLater); connect(thread, QThread::finished, thread, QThread::deleteLater); thread-start(); // 10秒后退出 QTimer::singleShot(10000, [](){ QApplication::quit(); }); return app.exec(); }

更多文章