| 類 | 用途 |
QThread | 管理線程,重寫 run() 或移動 QObject 到線程 |
QMutex | 互斥鎖,配合 QMutexLocker RAII |
QReadWriteLock | 讀寫鎖,多讀單寫,配合 QReadLocker/QWriteLocker |
QSemaphore | 信號量,控制有限資源訪問 |
QWaitCondition | 條件變量,線程等待/喚醒 |
QThreadStorage | 線程局部存儲 |
2. 創建線程:兩種模式
模式 A:繼承 QThread 重寫 run()
class WorkerThread : public QThread {
Q_OBJECT
protected:
void run() override {
// 線程入口,執行耗時任務
for (int i=0; i<100; ++i) {
// 工作...
msleep(10);
}
emit finished();
}
signals:
void finished();
};
// 使用
WorkerThread *thread = new WorkerThread;
connect(thread, &WorkerThread::finished, thread, &QObject::deleteLater);
thread->start();
模式 B:Worker QObject + moveToThread(推薦)
class Worker : public QObject {
Q_OBJECT
public slots:
void doWork() {
// 耗時任務
emit resultReady(data);
}
signals:
void resultReady(const QString &data);
};
// 使用
QThread *thread = new QThread;
Worker *worker = new Worker;
worker->moveToThread(thread);
connect(thread, &QThread::started, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &MainWindow::handleResult);
connect(worker, &Worker::resultReady, thread, &QThread::quit);
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
connect(worker, &Worker::destroyed, thread, &QThread::quit);
thread->start();
優勢:Worker 可有槽/信號、事件循環、定時器、網絡請求,生命週期管理更清晰。
3. 同步機制代碼模板
QMutex 保護共享數據
class Counter {
QMutex mutex;
int value = 0;
public:
void increment() { QMutexLocker locker(&mutex); ++value; }
int get() { QMutexLocker locker(&mutex); return value; }
};
QReadWriteLock 多讀優化
QReadWriteLock lock;
void read() { QReadLocker locker(&lock); /* 讀取共享數據 */ }
void write() { QWriteLocker locker(&lock); /* 修改共享數據 */ }
QSemaphore 生產者-消費者
const int BufferSize = 8192;
char buffer[BufferSize];
QSemaphore freeBytes(BufferSize), usedBytes(0);
void producer() {
for (int i=0; i
QWaitCondition 條件等待
QMutex mutex;
QWaitCondition notEmpty, notFull;
int used = 0;
void producer() {
mutex.lock();
while (used == BufferSize) notFull.wait(&mutex);
buffer[used++] = data;
notEmpty.wakeOne();
mutex.unlock();
}
void consumer() {
mutex.lock();
while (used == 0) notEmpty.wait(&mutex);
data = buffer[--used];
notFull.wakeOne();
mutex.unlock();
}
4. 可重入 vs 線程安全
| 概念 | 定義 | 典型類 |
| 可重入 | 同一類的不同實例可被多線程同時調用 | 大多數 C++ 類、Qt 非 GUI 類(QTimer, QTcpSocket...) |
| 線程安全 | 同一實例可被多線程同時調用 | QMutex, QAtomicInt, QCoreApplication::postEvent() |
規則:Qt 類默認可重入非線程安全。GUI 類(QWidget 及子類)不可重入,只能在主線程使用。
5. QObject 線程親緣性三大鐵律
- 子對象必須在父對象線程創建:不可將
QThread 對象作為父對象(它在另一線程創建)。
- 事件驅動對象綁定創建線程:定時器、網絡套接字必須在其所屬線程中啟動/連接。
- 刪除前清理:線程結束前刪除該線程創建的所有對象,或用
deleteLater() 安全跨線程刪除。
6. 跨線程信號槽:三種連接類型
| 類型 | 行為 | 執行線程 | 適用場景 |
| Direct | 立即調用槽 | 發射者線程 | 同線程、或確保線程安全 |
| Queued | 事件隊列投遞,事件循環處理 | 接收者線程 | 跨線程、默認安全 |
| Auto (默認) | 同線程=Direct,異線程=Queued | 自動 | 大多數情況 |
// 顯式指定
connect(sender, &Sender::signal, receiver, &Receiver::slot, Qt::QueuedConnection);
7. 隱式共享與線程安全
Qt 值類型(QString, QByteArray, QList, QImage...)使用原子引用計數的隱式共享(Copy-on-Write)。
- 跨線程傳值安全:引用計數原子操作,拷貝極廉價。
- 同一對象多線程讀寫不安全:需外部鎖保護(如
QMutex)。
- Qt 4.0+ 保證:原子操作用汇編實現,無鎖開銷,比手工 mutex 快得多。
8. 事件循環與跨線程事件投遞
- 主線程:
QCoreApplication::exec()。
- 子線程:
QThread::exec()(在 run() 中調用)。
QCoreApplication::postEvent():線程安全,向任意線程對象投遞事件。
sendEvent():同步直接投遞,僅用於當前線程。
總結:Qt 多線程最佳實踐清單
- 優先用 Worker + moveToThread,避免繼承 QThread。
- 共享數據用 QMutex/QReadWriteLock,RAII 用
QMutexLocker。
- 生產消費用 QSemaphore 或
QWaitCondition。
- 跨線程通信用 QueuedConnection 信號槽,傳值類型利用隱式共享。
- GUI 操作只在主線程,耗時任務拋給工作線程。
- 線程對象用
deleteLater(),確保事件處理完再銷毀。
- 用
QThreadStorage 管理線程局部數據。
掌握這套體系,即可編寫高併發、響應迅速、線程安全的 Qt 應用。
- 上一篇文章: Qt5 獲取本機網絡信息:IP、主機名、MAC、子網掩碼、廣播地址
- 下一篇文章: C語言進程間通信:管道機制概述與三種管道對比
Copyright ©
程式碼之家 All Rights Reserved