在Qt中實現多線程主要有兩種常用方式:基于QThread的子類化和QObject+moveToThread的Worker模式。以下是詳細說明和示例代碼:
1. 傳統方法:繼承 QThread(適用于簡單任務)
#include <QThread>
#include <QDebug>class MyThread : public QThread {Q_OBJECT
protected:void run() override {for(int i=0; i<5; i++){qDebug() << "Thread:" << i;sleep(1); // 模擬耗時操作}}
};// 使用方式
MyThread thread;
thread.start(); // 啟動線程
thread.wait(); // 等待線程結束(可選)
注意:
- 直接在
run()
中編寫業務邏輯,但不要在此線程中操作GUI組件。 - Qt4時代的經典方法,Qt5之后推薦Worker模式。
2. 推薦方法:Worker對象 + moveToThread(事件驅動)
#include <QObject>
#include <QThread>
#include <QDebug>class Worker : public QObject {Q_OBJECT
public slots:void doWork() {for(int i=0; i<5; i++){qDebug() << "Worker in thread:" << QThread::currentThreadId();QThread::sleep(1);}emit workFinished();}
signals:void workFinished();
};// 使用方式
QThread *thread = new QThread;
Worker *worker = new Worker;
worker->moveToThread(thread);// 連接信號與槽
QObject::connect(thread, &QThread::started, worker, &Worker::doWork);
QObject::connect(worker, &Worker::workFinished, thread, &QThread::quit);
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
QObject::connect(thread, &QThread::finished, worker, &QObject::deleteLater);thread->start(); // 啟動線程事件循環
優勢:
- 利用Qt的事件循環,避免阻塞線程。
- 通過信號槽實現線程間通信,天然線程安全。
- 資源管理更清晰,通過
deleteLater
自動釋放對象。
3. 線程安全與信號槽
- 跨線程通信:Qt信號槽自動排隊(QueuedConnection),無需手動同步。
- 共享數據保護:使用
QMutexLocker
或QReadWriteLock
保護臨界區。
// 示例:使用QMutex保護共享數據
QString sharedData;
QMutex mutex;void modifyData() {QMutexLocker locker(&mutex);sharedData = "Modified";
}
4. 線程池(QRunnable)
適用于需要頻繁創建/銷毀線程的場景:
#include <QRunnable>
#include <QThreadPool>class Task : public QRunnable {void run() override {qDebug() << "Task running in thread pool";}
};// 使用方式
Task *task = new Task;
QThreadPool::globalInstance()->start(task);
關鍵注意事項
- GUI操作限制:所有界面操作必須在主線程完成,通過信號將結果傳遞回UI線程。
- 事件循環:Worker模式依賴線程的事件循環(默認已啟動)。
- 資源釋放:通過
finished
信號觸發deleteLater
,避免野指針。 - 避免阻塞:耗時應放在子線程,主線程保持響應。
示例場景:后臺計算更新進度
// Worker類中定義進度信號
signals:void progressUpdated(int percent);// UI線程連接信號
QObject::connect(worker, &Worker::progressUpdated, [](int value){ progressBar->setValue(value); });
通過上述方法,Qt多線程編程既能保持界面流暢,又能高效利用多核CPU資源。