首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

Qt 多線程開發實戰:從基礎到 OpenGL 渲染線程分離

     編輯:關於C

Qt 提供跨平台線程支援,核心類包括 QThread、線程安全的事件傳遞(信號槽)、全域互斥鎖。本文通過實例演示如何將耗時計算移出 GUI 線程,並探討 OpenGL 渲染線程分離技巧。

核心概念

  • 主線程 (GUI 線程):程式啟動自動創建,所有 GUI 元件 (QWidget, QPixmap 等) 必須在此線程創建/操作。
  • 工作者線程:處理耗時任務(計算、IO、輪詢),通過信號槽與主線程通訊。

案例一:避免界面卡死的計算線程

單線程版本(界面凍結)

點擊「計算 Pi」按鈕,主線程執行億次循環,界面無響應,甚至無法關閉視窗。

多線程重構

  1. 繼承 QThread,重寫 run() 執行計算。
  2. 定義信號 computeFinish(double) 發送結果。
  3. 主視窗創建線程對象,連接信號到槽 slotShowResult(double) 更新標籤。
  4. 按鈕點擊調用 thread->start() 啟動線程。
// ComputeThread.h
class ComputeThread : public QThread {
    Q_OBJECT
protected:
    void run() override;
signals:
    void computeFinish(double result);
};

// ComputeThread.cpp
void ComputeThread::run() {
    double result = 0;
    for (int i = 1; i <= 1000000000; ++i) {
        double val = 4.0 / (2*i - 1);
        result += (i % 2) ? val : -val;
    }
    emit computeFinish(result);
}

// MainWindow.cpp
connect(computeThread, &ComputeThread::computeFinish, this, &MainWindow::slotShowResult);
connect(btnCalc, &QPushButton::clicked, computeThread, &QThread::start);

結果:計算期間界面流暢,「Say Hi」按鈕即時響應。

案例二:OpenGL 持續渲染線程

場景:QGLWidget 需持續動畫(如旋轉三角形),主線程死循環會阻塞事件處理。

方案:專用渲染線程 GLThread

  1. GLThread 持有 GLWidget*,在 run() 中調用 makeCurrent() 綁定 OpenGL 上下文。
  2. 循環執行:更新角度 → glClear → 繪製 → swapBuffers() → msleep(50) 控制幀率。
  3. resizeViewport() 通過標誌位 doResize 線程安全傳遞新尺寸。
  4. GLWidget 轉發 resizeEvent 到線程,paintEvent 留空(由線程接管)。
void GLThread::run() {
    glw->makeCurrent();
    // 初始化投影矩陣...
    while (doRendering) {
        if (doResize) { /* 更新 viewport & 投影 */ doResize = false; }
        rotAngle += 5; if (rotAngle >= 360) rotAngle = 0;
        // 繪製三角形...
        glw->swapBuffers();
        msleep(50);
    }
}

線程間數據訪問方式對比

方式適用場景注意事項
信號槽 (QueuedConnection)跨線程傳遞數據、觸發 GUI 更新線程安全,參數需註冊元類型
指針直接訪問高頻、低延遲共享數據(如 OpenGL 上下文)需手動加鎖 (QMutex),避免競態
QMetaObject::invokeMethod跨線程調用槽函數支援同步/異步

最佳實踐提醒

  • GUI 類不可在非主線程實例化,OpenGL 上下文需在渲染線程 makeCurrent()。
  • 線程結束前調用 quit() + wait() 確保資源釋放。
  • 共享數據用 QMutex/QReadWriteLock 保護,或用無鎖隊列傳遞命令。
  • Qt 5+ 推薦「Worker Object + moveToThread」模式替代繼承 QThread,更靈活。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved