QT異步線程通信

在使用 QThreadPool 提交任務后,如果你需要知道任務何時完成,并且需要使用任務的執行結果,可以通過以下幾種方式來實現:

1. 使用信號和槽

QRunnable 提供了一個 finished() 信號,當任務執行完成后會發出。你可以在任務完成后通過信號和槽機制通知主線程。

示例代碼
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>
#include <QThread>class Worker : public QRunnable {
public:Worker() {// 連接 finished 信號到自定義槽connect(this, &Worker::finished, this, &Worker::onFinished);}void run() override {qDebug() << "Worker running in thread" << QThread::currentThreadId();// 模擬耗時任務QThread::sleep(3);qDebug() << "Worker finished";emit finished(); // 發出任務完成信號}private slots:void onFinished() {qDebug() << "Worker finished in thread" << QThread::currentThreadId();// 在這里可以處理任務完成后的邏輯}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);// 獲取全局線程池QThreadPool* globalThreadPool = QThreadPool::globalInstance();// 創建一個任務Worker* worker = new Worker();// 將任務添加到全局線程池qDebug() << "Starting worker in main thread" << QThread::currentThreadId();globalThreadPool->start(worker);// 主線程繼續運行qDebug() << "Main thread continues running immediately";QThread::sleep(1); // 等待一段時間,觀察輸出qDebug() << "Main thread still running";return app.exec();
}

輸出示例

Starting worker in main thread 0x1234
Main thread continues running immediately
Main thread still running
Worker running in thread 0x5678
Worker finished
Worker finished in thread 0x5678

2. 使用 QFutureQtConcurrent::run

如果你需要更靈活的異步任務管理,可以使用 QtConcurrent::run,它會返回一個 QFuture 對象,你可以通過它來檢查任務的狀態或獲取任務的返回值。

示例代碼
#include <QCoreApplication>
#include <QtConcurrent>
#include <QDebug>
#include <QThread>
#include <QFuture>
#include <QFutureWatcher>int workerFunction() {qDebug() << "Worker running in thread" << QThread::currentThreadId();// 模擬耗時任務QThread::sleep(3);qDebug() << "Worker finished";return 42; // 返回結果
}int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);// 使用 QtConcurrent::run 提交任務QFuture<int> future = QtConcurrent::run(workerFunction);// 主線程繼續運行qDebug() << "Main thread continues running immediately";QThread::sleep(1); // 等待一段時間,觀察輸出qDebug() << "Main thread still running";// 等待任務完成并獲取結果qDebug() << "Waiting for worker to finish...";int result = future.result(); // 阻塞主線程,直到任務完成qDebug() << "Worker result:" << result;return app.exec();
}

輸出示例

Main thread continues running immediately
Main thread still running
Worker running in thread 0x5678
Worker finished
Waiting for worker to finish...
Worker result: 42

3. 使用 QThreadPool::waitForDone()

如果你需要等待所有任務完成,可以使用 QThreadPool::waitForDone() 方法。這個方法會阻塞當前線程,直到線程池中的所有任務都完成。

示例代碼
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>
#include <QThread>class Worker : public QRunnable {
public:void run() override {qDebug() << "Worker running in thread" << QThread::currentThreadId();// 模擬耗時任務QThread::sleep(3);qDebug() << "Worker finished";}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);// 獲取全局線程池QThreadPool* globalThreadPool = QThreadPool::globalInstance();// 創建一個任務Worker* worker = new Worker();// 將任務添加到全局線程池qDebug() << "Starting worker in main thread" << QThread::currentThreadId();globalThreadPool->start(worker);// 主線程繼續運行qDebug() << "Main thread continues running immediately";QThread::sleep(1); // 等待一段時間,觀察輸出qDebug() << "Main thread still running";// 等待所有任務完成qDebug() << "Waiting for all tasks to finish...";globalThreadPool->waitForDone();qDebug() << "All tasks finished";return app.exec();
}

輸出示例

Starting worker in main thread 0x1234
Main thread continues running immediately
Main thread still running
Worker running in thread 0x5678
Worker finished
Waiting for all tasks to finish...
All tasks finished

總結

  • 信號和槽:通過 QRunnable::finished 信號通知任務完成。
  • QFutureQtConcurrent::run:提供更靈活的異步任務管理,可以獲取任務的返回值。
  • QThreadPool::waitForDone:等待線程池中的所有任務完成,但會阻塞當前線程。

根據你的需求選擇合適的方法。如果你需要任務的返回值,建議使用 QtConcurrent::runQFuture


QtConcurrent::run 和直接使用 QThread 在功能和使用方式上有顯著的區別。以下是它們的主要區別:

1. 使用方式

  • QtConcurrent::run

    • 更簡單QtConcurrent::run 是一個高級接口,用于簡化異步任務的提交和管理。它返回一個 QFuture 對象,可以用來檢查任務的狀態或獲取任務的返回值。
    • 無需手動管理線程:你只需要提供一個函數或 lambda 表達式,QtConcurrent::run 會自動將任務提交到線程池中執行,無需手動創建和管理 QThread
    • 支持返回值QFuture 可以存儲任務的返回值,方便在任務完成后獲取結果。
  • QThread

    • 更靈活QThread 是一個低級接口,提供了對線程的細粒度控制。你可以創建自己的線程類,管理線程的啟動、停止和同步。
    • 需要手動管理線程:你需要手動創建線程,連接信號和槽,管理線程的生命周期。
    • 不直接支持返回值:線程的執行結果需要通過信號和槽或其他機制傳遞回主線程。

2. 線程管理

  • QtConcurrent::run

    • 使用線程池QtConcurrent::run 內部使用 QThreadPool 來管理線程。任務會被提交到全局線程池中,由線程池負責分配線程。這種方式可以減少線程創建和銷毀的開銷,提高性能。
    • 自動管理線程生命周期:任務完成后,線程會自動返回線程池,無需手動管理。
  • QThread

    • 手動管理線程:你需要手動創建和啟動線程,并在任務完成后手動停止線程。
    • 線程生命周期:線程的生命周期由你控制,需要確保線程在任務完成后正確退出。

3. 任務狀態和結果

  • QtConcurrent::run

    • QFuture 提供狀態檢查QFuture 提供了多種方法來檢查任務的狀態,例如:
      • isFinished():檢查任務是否完成。
      • isRunning():檢查任務是否正在運行。
      • result():獲取任務的返回值。
    • 支持異步操作QFuture 可以與 QFutureWatcher 配合使用,通過信號和槽機制在任務完成時通知主線程。
  • QThread

    • 手動檢查狀態:你需要通過信號和槽機制或手動檢查線程的狀態。
    • 不直接支持返回值:線程的執行結果需要通過信號和槽或其他機制傳遞回主線程。

4. 適用場景

  • QtConcurrent::run

    • 簡單任務:適用于簡單的異步任務,特別是那些不需要復雜線程管理的場景。
    • 任務結果處理:當你需要獲取任務的返回值時,QFuture 提供了方便的接口。
  • QThread

    • 復雜任務:適用于需要更細粒度控制線程的復雜任務。
    • 長時間運行的任務:適用于需要長時間運行的后臺任務,例如網絡通信、文件處理等。

示例對比

使用 QtConcurrent::run
#include <QCoreApplication>
#include <QtConcurrent>
#include <QDebug>
#include <QThread>int workerFunction() {qDebug() << "Worker running in thread" << QThread::currentThreadId();QThread::sleep(3);qDebug() << "Worker finished";return 42; // 返回結果
}int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);// 提交任務QFuture<int> future = QtConcurrent::run(workerFunction);// 主線程繼續運行qDebug() << "Main thread continues running immediately";QThread::sleep(1);// 等待任務完成并獲取結果qDebug() << "Waiting for worker to finish...";int result = future.result();qDebug() << "Worker result:" << result;return app.exec();
}
使用 QThread
#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QMutex>
#include <QWaitCondition>class Worker : public QObject {Q_OBJECT
public:Worker() : result(0), finished(false) {}void run() {qDebug() << "Worker running in thread" << QThread::currentThreadId();QThread::sleep(3);result = 42; // 設置結果finished = true; // 標記任務完成condition.wakeOne(); // 通知主線程}int getResult() const { return result; }bool isFinished() const { return finished; }signals:void finished();private:mutable QMutex mutex;QWaitCondition condition;int result;bool finished;
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);Worker worker;QThread thread;worker.moveToThread(&thread);QObject::connect(&thread, &QThread::started, &worker, &Worker::run);thread.start();qDebug() << "Main thread continues running immediately";QThread::sleep(1);// 等待任務完成qDebug() << "Waiting for worker to finish...";QMutexLocker locker(&worker.mutex);while (!worker.isFinished()) {worker.condition.wait(&locker);}int result = worker.getResult();qDebug() << "Worker result:" << result;thread.quit();thread.wait();return app.exec();
}

總結

  • QtConcurrent::run

    • 優點:簡單易用,自動管理線程,支持返回值。
    • 缺點:功能相對有限,適合簡單任務。
    • 適用場景:適合簡單的異步任務,特別是需要獲取任務結果的場景。
  • QThread

    • 優點:功能強大,支持復雜的線程管理。
    • 缺點:使用復雜,需要手動管理線程。
    • 適用場景:適合需要細粒度控制線程的復雜任務。

根據你的需求選擇合適的方式。如果你的任務簡單且需要返回值,推薦使用 QtConcurrent::run。如果你的任務復雜且需要更細粒度的線程管理,推薦使用 QThread


在 Qt 中,QFuture 是一個線程安全的對象,用于表示異步操作的結果。當你將 QFuture 作為值傳遞給其他函數時,實際上傳遞的是一個輕量級的“未來”對象的副本。這個副本與原始的 QFuture 對象共享底層的異步操作狀態。

關鍵點

  • 共享狀態:盡管 QFuture 是按值傳遞的,但它內部維護的是一個共享的狀態。這意味著,無論你傳遞了多少個副本,它們都會指向同一個底層的異步操作狀態。
  • 線程安全QFuture 的狀態是線程安全的,因此你可以在多個線程中安全地訪問和修改它的狀態。

示例

假設你有以下代碼:

void MachineFileBrowser::handleSingleClick(const QModelIndex &index)
{if (index.isValid() && lastClickedIndex == index){QString path = model->getFilePath(index);fileloadFuture = QtConcurrent::run([this, path]() {MachineTree &tempTree = currentTemplate->getMachineTree();tempTree = MachineTree::parseFromTarXmlFile(path);  // 解析機器樹數據});emit itemReClicked(index, fileloadFuture);} else{lastClickedIndex = index;}
}

itemReClicked 信號的槽函數中,你可以這樣處理:

void SomeClass::handleItemReClicked(const QModelIndex &index, QFuture<void> future)
{// 檢查任務是否完成if (future.isFinished()){qDebug() << "Task is finished";}else{qDebug() << "Task is still running";}
}

關鍵點解釋

  1. fileloadFuture 的狀態

    • fileloadFuture 是一個 QFuture<void> 對象,它表示一個異步操作的未來結果。
    • 當你將 fileloadFuture 傳遞給 itemReClicked 信號時,傳遞的是一個副本,但這個副本與原始的 fileloadFuture 共享底層的狀態。
  2. 狀態同步

    • 無論你在哪個地方訪問 fileloadFuture,它的狀態(例如 isFinished())始終是同步的。這是因為 QFuture 內部使用了共享的狀態機制。
    • 這意味著,即使你在多個地方持有 fileloadFuture 的副本,它們的狀態始終是一致的。

示例代碼

假設你有一個槽函數 handleItemReClicked,它接收 fileloadFuture 的副本:

void SomeClass::handleItemReClicked(const QModelIndex &index, QFuture<void> future)
{// 檢查任務是否完成if (future.isFinished()){qDebug() << "Task is finished";}else{qDebug() << "Task is still running";}
}

handleSingleClick 中,你發射了 itemReClicked 信號:

emit itemReClicked(index, fileloadFuture);

在槽函數中,你可以通過 future.isFinished() 檢查任務是否完成。無論任務是否完成,future.isFinished() 的結果始終是正確的,因為 QFuture 的狀態是共享的。

總結

  • QFuture 的狀態是共享的:即使你將 QFuture 作為值傳遞,它的狀態仍然是共享的。
  • 線程安全QFuture 的狀態是線程安全的,你可以在多個線程中安全地訪問和修改它的狀態。
  • 狀態同步:無論你在哪個地方訪問 QFuture,它的狀態始終是一致的。

因此,即使 fileloadFuture 是按值傳遞的,你仍然可以在其他函數中通過 isFinished() 檢查任務的狀態,并且結果始終是正確的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/80093.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/80093.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/80093.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

利用并行處理提高LabVIEW程序執行速度

在 LabVIEW 編程中&#xff0c;提升程序執行速度是優化系統性能的關鍵&#xff0c;而并行處理技術則是實現這一目標的有力武器。通過合理運用并行處理&#xff0c;不僅能加快程序運行&#xff0c;還能增強系統的穩定性和響應能力。下面將結合實際案例&#xff0c;深入探討如何利…

機器學習第三講:監督學習 → 帶答案的學習冊,如預測房價時需要歷史價格數據

機器學習第三講&#xff1a;監督學習 → 帶答案的學習冊&#xff0c;如預測房價時需要歷史價格數據 資料取自《零基礎學機器學習》。 查看總目錄&#xff1a;學習大綱 關于DeepSeek本地部署指南可以看下我之前寫的文章&#xff1a;DeepSeek R1本地與線上滿血版部署&#xff1…

Open CASCADE學習|實現裁剪操作

1. 引言 Open CASCADE (簡稱OCC) 是一個功能強大的開源幾何建模內核&#xff0c;廣泛應用于CAD/CAM/CAE領域。裁剪操作作為幾何建模中的基礎功能&#xff0c;在模型編輯、布爾運算、幾何分析等方面有著重要作用。本文將全面探討Open CASCADE中的裁剪操作實現原理、應用場景及具…

【redis】分片方案

Redis分片&#xff08;Sharding&#xff09;是解決單機性能瓶頸的核心技術&#xff0c;其本質是將數據分散存儲到多個Redis節點&#xff08;實例&#xff09;中&#xff0c;每個實例將只是所有鍵的一個子集&#xff0c;通過水平擴展提升系統容量和性能。 分片的核心價值 性能提…

RGB矩陣照明系統詳解及WS2812配置指南

RGB矩陣照明系統詳解及WS2812配置指南 一、RGB矩陣照明簡介 RGB矩陣照明是一種強大的功能&#xff0c;允許使用外部驅動器驅動的RGB LED矩陣為鍵盤增添絢麗的燈光效果。該系統與RGBLIGHT功能無縫集成&#xff0c;因此您可以使用與RGBLIGHT相同的鍵碼來控制它&#xff0c;操作…

[250509] x-cmd 發布 v0.5.11 beta:x ping 優化、AI 模型新增支持和語言變量調整

目錄 X-CMD 發布 v0.5.11 beta&#x1f4c3;Changelog&#x1f9e9; ping&#x1f9e9; openai&#x1f9e9; gemini&#x1f9e9; asdf&#x1f9e9; mac? 升級指南 X-CMD 發布 v0.5.11 beta &#x1f4c3;Changelog &#x1f9e9; ping 調整 x ping 默認參數為 bing.com&a…

嵌入式開發學習日志Day17

第十一章 結構體與共用體 一、結構體 1、結構體 一般形式 【struct 標識符】 結構體中的標識符一般首字母大寫&#xff1b; 【.】結構體成員運算符&#xff1b; 優先級 1 級 結合方向&#xff1a;從左至右&#xff1b; 【->】:指向結構體成員運算符&#x…

發那科機器人5(異常事件和程序備份加載+ROBOGUIDE離線仿真)

發那科機器人5(異常事件和程序備份加載+ROBOGUIDE離線仿真) 一,異常事件和程序備份加載1,常見異常事件2,零點復歸介紹3,程序備份-加載(未整理)二,`ROBOGUIDE`離線仿真1,仿真軟件簡介及安裝步驟(未整理)2,機器人==導入與工具==與==工件添加==2.1,機器人導入(未整…

青少年編程與數學 02-019 Rust 編程基礎 01課題、環境準備

青少年編程與數學 02-019 Rust 編程基礎 01課題、環境準備 一、Rust核心特性應用場景開發工具社區與生態 二、Rust 和 Python 比較1. **內存安全與并發編程**2. **性能**3. **零成本抽象**4. **跨平臺支持**5. **社區與生態系統**6. **錯誤處理**7. **安全性**適用場景總結 三、…

Java反射 八股版

目錄 一、核心概念闡釋 1. Class類 2. Constructor類 3. Method類 4. Field類 二、典型應用場景 1. 框架開發 2. 單元測試 3. JSON序列化/反序列化 三、性能考量 四、安全與訪問控制 1. 安全管理器限制 2. 打破封裝性 3. 安全風險 五、版本兼容性問題 六、最佳…

操作系統的初步了解

目錄 引言&#xff1a;什么是操作系統&#xff1f; 一、設計操作系統的目的 二、操作系統是做什么的&#xff1a; 操作系統主要有四大核心任務&#xff1a; 1. 管理硬件 2. 運行軟件 3. 存儲數據 4. 提供用戶界面 如何理解操作系統的管理呢&#xff1f; 1. 什么是操作…

Mkdocs頁面如何嵌入PDF

嵌入PDF 嵌入PDF代碼 &#xff0c;注意PDF的相對地址 <iframe src"../個人簡歷.pdf (相對地址)" width"100%" height"800px" style"border: 1px solid #ccc; overflow: auto;"></iframe>我的完整代碼&#xff1a; <d…

鏈表結構深度解析:從單向無頭到雙向循環的實現全指南

上篇博客實現動態順序表時&#xff0c;我們會發現它存在許多弊端&#xff0c;如&#xff1a; ? 中間/頭部的插?刪除&#xff0c;時間復雜度為O(N) ? 增容需要申請新空間&#xff0c;拷?數據&#xff0c;釋放舊空間。會有不?的消耗。 ? 增容?般是呈2倍的增?&#xff0c;…

@PostConstruct @PreDestroy

PostConstruct 是 Java EE&#xff08;現 Jakarta EE&#xff09;中的一個注解&#xff0c;用于標記一個方法在對象初始化完成后立即執行。它在 Spring 框架、Java Web 應用等場景中廣泛使用&#xff0c;主要用于資源初始化、依賴注入完成后的配置等操作。 1. 基本作用 執行時…

【ArcGIS微課1000例】0146:將多個文件夾下的影像移動到一個目標文件夾(以Landscan數據為例)

本文講述將多個文件夾下的影像移動到一個目標文件夾,便于投影變換、裁剪等操作。 文章目錄 一、數據準備二、解壓操作三、批量移動四、查看效果五、ArcGIS操作一、數據準備 全球人口數據集Landscan2000-2023如下所示,每年數據位一個壓縮包: 二、解壓操作 首先將其解壓,方…

專業級 GIF 制作工具深度解析:Gifski 與 GIPHY CAPTURE 的技術對比與實戰指南

《Gifski 與 GIPHY CAPTURE&#xff1a;GIF 制作工具的深度對比與實戰應用》 最近在嘗試做一些培訓文檔&#xff0c;需要使用GIF圖做動態效果&#xff0c;把工具選型過程給大家做一下分享。 先看一張對比表&#xff0c;具體如下&#xff1a; 場景 Windows macOS Linux 移…

selenium替代----playwright

安裝 好處特點&#xff1a;這個東西不像selenium需要固定版本的驅動 pip config set global.index-url https://mirrors.aliyun.com/pypi/simplepip install --upgrade pippip install playwright playwright installplaywright install ffmpeg (處理音視頻的)驗證&#x…

Python代碼編程基礎

字符串 str.[]實現根據下標定位實現對元素的截取 for 循環可以實現遍歷 while 循環可以在實現遍歷的同時實現對某一下標數值的修改 字符串前加 r 可以實現對字符串的完整內容輸出 字符串前加 f 可以實現對字符串內{}中包裹內容的格式化輸出&#xff0c;僅在 v3.6 之后可用…

5月9號.

v-for: v-bind: v-if&v-show: v-model: v-on: Ajax: Axios: async&await: Vue生命周期: Maven: Maven坐標:

Spring 必會之微服務篇(1)

目錄 引入 單體架構 集群和分布式架構 微服務架構 挑戰 Spring Cloud 介紹 實現方案 Spring Cloud Alibaba 引入 單體架構 當我們剛開始學開發的時候&#xff0c;基本都是單體架構&#xff0c;就是把一個項目的所有業務的實現功能都打包在一個 war 包或者 Jar 包中。…