最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Qt中多線程QThread、QThreadPool、QConCurrent三種方式對比分析

 更新時間:2026年05月25日 09:57:56   作者:追烽少年x  
QThread是Qt多線程的基石,本質(zhì)上是對操作系統(tǒng)原生線程的面向?qū)ο蠓庋b,本文介紹Qt中多線程QThread、QThreadPool、QConCurrent三種方式對比分析,感興趣的朋友一起看看吧

第一層:QThread —— 基石與底層控制(管理“線程”)

QThread 是 Qt 多線程的基石,本質(zhì)上是對操作系統(tǒng)原生線程的面向?qū)ο蠓庋b。

  • 核心思想:你直接創(chuàng)建和控制線程的生命周期。
  • 使用方式
    1. 繼承重寫法:繼承 QThread 重寫 run() 函數(shù)。簡單粗暴,但不夠靈活,線程和任務(wù)耦合在一起。
    2. moveToThread法:繼承 QObject,通過 object->moveToThread(thread) 將對象移入線程。這是 Qt 官方推薦的寫法,利用信號槽驅(qū)動任務(wù)執(zhí)行,線程與任務(wù)解耦。
  • 優(yōu)點:控制力最強。你可以精確控制線程的優(yōu)先級、棧大小、啟動、停止、甚至是線程內(nèi)的事件循環(huán)。
  • 缺點:開銷大(線程創(chuàng)建/銷毀系統(tǒng)開銷大);管理難(如果隨手 new QThread,容易導(dǎo)致線程數(shù)量失控);不適合海量短任務(wù)。
  • 適用場景常駐線程。比如后臺一直運行的硬件通信輪詢、服務(wù)器監(jiān)聽、需要獨立事件循環(huán)處理信號槽的長生命周期任務(wù)。

代碼示例:

  1. QThread (moveToThread 法) —— 面向?qū)ο?,事件循環(huán)驅(qū)動

這是 Qt 官方推薦的做法。我們將創(chuàng)建一個 Worker 類,將其移入 QThread,通過信號槽觸發(fā)任務(wù)并返回結(jié)果。

核心特征:線程常駐、支持信號槽、擁有獨立事件循環(huán)。

#include <QCoreApplication>
#include <QThread>
#include <QObject>
#include <QDebug>
// 1. 定義工作類(千萬不要繼承QThread)
class Worker : public QObject {
    Q_OBJECT
public:
    explicit Worker(int id) : m_id(id) {}
public slots:
    // 槽函數(shù):執(zhí)行耗時任務(wù)
    void doWork() {
        qDebug() << "Worker" << m_id << "running in thread:" << QThread::currentThreadId();
        QThread::msleep(1000); // 模擬耗時操作
        int result = m_id * 100; // 模擬計算結(jié)果
        emit resultReady(m_id, result); // 發(fā)送結(jié)果信號
    }
signals:
    void resultReady(int id, int result);
private:
    int m_id;
};
int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    qDebug() << "Main thread:" << QThread::currentThreadId();
    QList<QThread*> threads;
    QList<Worker*> workers;
    // 創(chuàng)建 5 個工作對象和 5 個線程
    for (int i = 0; i < 5; ++i) {
        Worker *worker = new Worker(i);
        QThread *thread = new QThread();
        worker->moveToThread(thread); // 將工作對象移入新線程
        // 連接啟動信號:線程啟動后,調(diào)用 worker 的 doWork
        QObject::connect(thread, &QThread::started, worker, &Worker::doWork);
        // 連接結(jié)果信號:將結(jié)果打印到主線程
        QObject::connect(worker, &Worker::resultReady, [](int id, int result){
            qDebug() << "  -> Got result from Worker" << id << ":" << result;
        });
        // 連接清理信號:任務(wù)完成后,安全退出線程并清理內(nèi)存
        QObject::connect(worker, &Worker::resultReady, thread, &QThread::quit);
        QObject::connect(thread, &QThread::finished, worker, &QObject::deleteLater);
        QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);
        threads.append(thread);
        workers.append(worker);
    }
    // 啟動所有線程
    for (QThread *t : threads) {
        t->start();
    }
    return a.exec();
}

代碼運行結(jié)果:

第二層:QThreadPool + QRunnable —— 任務(wù)池化(管理“任務(wù)”)

隨著需求的復(fù)雜,你發(fā)現(xiàn)頻繁創(chuàng)建銷毀 QThread 太浪費資源,于是進階到了線程池。QRunnable 是任務(wù),QThreadPool 是執(zhí)行任務(wù)的池子。

  • 核心思想:將“線程”和“任務(wù)”解耦。你只需要寫任務(wù),線程的創(chuàng)建、復(fù)用、銷毀交給線程池。
  • 使用方式:繼承 QRunnable 重寫 run(),然后丟給 QThreadPool::start()
  • 進階體現(xiàn)
    1. 資源復(fù)用:避免了頻繁創(chuàng)建/銷毀線程的系統(tǒng)調(diào)用。
    2. 并發(fā)控制:通過 maxThreadCount() 限制最大并發(fā)數(shù),防止系統(tǒng)資源耗盡。
  • 缺點QRunnable 本身不是繼承自 QObject不支持信號槽(雖然可以手動使用 QMetaObject::invokeMethod 或組合 QObject 來解決,但終歸麻煩);缺乏取消、進度匯報等高級功能。
  • 適用場景大量獨立的、無狀態(tài)的短任務(wù)。比如批量處理圖片、批量下載文件、并發(fā)的數(shù)學(xué)計算。丟進池子,跑完即止。

代碼示例:

  1. QThreadPool + QRunnable —— 任務(wù)池化,拿來即走

我們將任務(wù)封裝為 QRunnable,丟給全局線程池。因為 QRunnable 不是 QObject,無法直接使用信號槽,這里我們使用 C++11 的 std::function 回調(diào)來返回結(jié)果。

核心特征:線程復(fù)用、無事件循環(huán)、適合一次性短任務(wù)、需手動處理結(jié)果回傳。

#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>
// 1. 定義任務(wù)類
class ComputeTask : public QRunnable {
public:
    ComputeTask(int id, std::function<void(int, int)> callback) 
        : m_id(id), m_callback(callback) 
    {
        // 設(shè)置任務(wù)執(zhí)行完后自動銷毀,防止內(nèi)存泄漏
        setAutoDelete(true); 
    }
    // 重寫 run 函數(shù)
    void run() override {
        qDebug() << "Task" << m_id << "running in thread:" << QThread::currentThreadId();
        QThread::msleep(1000); // 模擬耗時操作
        int result = m_id * 100;
        // QRunnable 沒有信號槽,使用回調(diào)函數(shù)將結(jié)果傳回
        if (m_callback) {
            m_callback(m_id, result);
        }
    }
private:
    int m_id;
    std::function<void(int, int)> m_callback;
};
int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    qDebug() << "Main thread:" << QThread::currentThreadId();
    // 設(shè)置全局線程池最大線程數(shù)為 2(為了演示線程復(fù)用)
    QThreadPool::globalInstance()->setMaxThreadCount(2);
    for (int i = 0; i < 5; ++i) {
        // 定義回調(diào)函數(shù)接收結(jié)果
        auto callback = [](int id, int result) {
            qDebug() << "  -> Got result from Task" << id << ":" << result;
        };
        ComputeTask *task = new ComputeTask(i, callback);
        // 丟給線程池執(zhí)行
        QThreadPool::globalInstance()->start(task);
    }
    // 等待所有任務(wù)完成再退出(僅為了演示,實際GUI程序不推薦主線程wait)
    QThreadPool::globalInstance()->waitForDone();
    qDebug() << "All tasks finished.";
    return 0; // 不需要 a.exec(),因為沒有事件循環(huán)
}

代碼運行結(jié)果:

第三層:QtConcurrent —— 高層函數(shù)式并發(fā)(管理“結(jié)果”)

當你要處理的不僅是任務(wù),而是數(shù)據(jù)集合(比如一個 List 里的所有元素都要做相同操作),QRunnable 寫起來還是很啰嗦(要寫類、要重寫run、要處理數(shù)據(jù)傳遞)。于是進階到了 QtConcurrent

  • 核心思想:聲明式編程。你只需要告訴 Qt “對這堆數(shù)據(jù)執(zhí)行什么函數(shù)”,Qt 自動幫你分配到線程池(底層默認使用全局 QThreadPool)。
  • 使用方式QtConcurrent::map() / filter() / mappedReduced() / run()。配合 C++11 的 Lambda 表達式,代碼極其精簡。
  • 進階體現(xiàn)
    • 極簡 API:一行代碼即可實現(xiàn)多并發(fā)。
    • QFuture 綁定:返回 QFuture 對象,可以隨時查詢計算進度(progressValue)、掛起(suspend)、恢復(fù)(resume)、取消(cancel)以及獲取最終結(jié)果。
    • 自動負載均衡:根據(jù) CPU 核心數(shù)自動切分數(shù)據(jù)塊,實現(xiàn)最佳負載均衡。
    • 缺點:靈活性最低。無法控制任務(wù)具體跑在哪個線程,無法像 QThread 那樣運行獨立的事件循環(huán)。
    • 適用場景數(shù)據(jù)并行處理。比如對一個包含 10000 個元素的 QList 同時求平方、過濾出符合條件的對象等。
  • 代碼示例:
    • 我們不再需要顯式定義類,直接使用 QtConcurrent::run 將一個 Lambda 表達式丟進線程池,并利用 QFutureWatcher 異步監(jiān)聽結(jié)果。
    • 核心特征:代碼極簡、自動數(shù)據(jù)分片、QFuture 提供進度/取消/結(jié)果監(jiān)聽、無需關(guān)心線程。
#include <QCoreApplication>
#include <QtConcurrent>
#include <QFutureWatcher>
#include <QDebug>
int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    qDebug() << "Main thread:" << QThread::currentThreadId();
    // 同樣限制全局線程池大小以便觀察
    QThreadPool::globalInstance()->setMaxThreadCount(2);
    // 使用 QFutureWatcher 監(jiān)聽異步結(jié)果(因為 QtConcurrent 本身是非阻塞的)
    QFutureWatcher<int> *watcher = new QFutureWatcher<int>();
    // 當單個結(jié)果就緒時觸發(fā)
    QObject::connect(watcher, &QFutureWatcher<int>::resultReadyAt, [](int index) {
        qDebug() << "  -> Result at index" << index << "is ready.";
    });
    // 當所有任務(wù)完成時觸發(fā)
    QObject::connect(watcher, &QFutureWatcher<int>::finished, [watcher]() {
        qDebug() << "All concurrent tasks finished.";
        // 獲取所有結(jié)果
        QFuture<int> future = watcher->future();
        for (int i = 0; i < future.resultCount(); ++i) {
            qDebug() << "    Final Result[" << i << "] =" << future.resultAt(i);
        }
        watcher->deleteLater();
        QCoreApplication::quit(); // 退出程序
    });
    // 使用 QtConcurrent::run 啟動并發(fā)任務(wù)
    // 返回 QFuture 對象用于跟蹤狀態(tài)
    QFuture<int> future = QtConcurrent::mapped(QList<int>() << 0 << 1 << 2 << 3 << 4, [](int id) -> int {
        qDebug() << "Concurrent task" << id << "running in thread:" << QThread::currentThreadId();
        QThread::msleep(1000); // 模擬耗時
        return id * 100;       // 直接返回結(jié)果
    });
    // 將 future 交給 watcher 監(jiān)控
    watcher->setFuture(future);
    return a.exec();
}

代碼運行結(jié)果:

四、對比小結(jié)

維度QThreadQThreadPool + QRunnableQtConcurrent
控制粒度線程級(最強)任務(wù)級數(shù)據(jù)級(最弱)
開發(fā)效率較低(需手動管理生命周期)中等(需封裝任務(wù)類)極高(一行代碼/Lambda)
事件循環(huán)支持(核心優(yōu)勢)不支持(默認無)不支持
信號槽完美支持不原生支持不支持(通過QFuture獲取結(jié)果)
底層依賴操作系統(tǒng) API依賴 QThread依賴 QThreadPool
核心場景常駐后臺、需事件循環(huán)大量獨立短任務(wù)數(shù)據(jù)集合的并行計算

從代碼看差異

  1. 代碼量與復(fù)雜度
    • QThread 代碼最臃腫。你需要管理 QObject、QThread 的創(chuàng)建、moveToThread、信號槽連接,以及極其重要的內(nèi)存清理邏輯finished -> deleteLater)。
    • QRunnable 適中。你需要繼承并重寫 run(),最關(guān)鍵的是要自己想辦法把結(jié)果“傳出來”(如回調(diào)、QMetaObject::invokeMethod),容易寫出回調(diào)地獄。
    • QtConcurrent 最清爽。不用寫類,不用管線程,一行 runmapped 搞定,配合 QFutureWatcher 獲取結(jié)果非常優(yōu)雅。
  2. 結(jié)果獲取方式
    • QThread:通過信號槽,天然線程安全,完美融入 Qt 事件循環(huán)。
    • QRunnable:通過回調(diào)/std::function,或者在 run() 里用 QMetaObject::invokeMethod 往主線程發(fā)信號,略顯生硬。
    • QtConcurrent:通過 QFuture / QFutureWatcher,這是 Qt 提供的高層抽象,不僅能拿結(jié)果,還能監(jiān)聽進度、取消任務(wù)。
  3. 生命周期與線程復(fù)用(重點體會)
    • QThread 示例中,5 個任務(wù)創(chuàng)建了 5 個真實的系統(tǒng)線程,任務(wù)完成后線程退出銷毀。
    • QRunnableQtConcurrent 示例中,我們設(shè)置了 setMaxThreadCount(2)。你會在運行輸出中發(fā)現(xiàn),5 個任務(wù)只創(chuàng)建了 2 個線程!前 2 個任務(wù)跑完后,線程沒死,接著跑后 2 個,實現(xiàn)了線程復(fù)用,大幅節(jié)省了系統(tǒng)資源。

選擇建議:

  • 如果你需要后臺一直跑(比如監(jiān)聽串口數(shù)據(jù)),用 QThread + moveToThread。
  • 如果你有一堆零碎的獨立任務(wù)(比如批量解析 100 個文件),用 QThreadPool + QRunnable。
  • 如果你只是想讓一段計算代碼在后臺跑別卡界面,或者要對一個列表里的數(shù)據(jù)并行處理,毫不猶豫選 QtConcurrent。

到此這篇關(guān)于Qt中多線程QThread、QThreadPool、QConCurrent三種方式對比分析的文章就介紹到這了,更多相關(guān)Qt 多線程QThread、QThreadPool、QConCurrent區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺談關(guān)于指針作為參數(shù)并改變它的值的問題

    淺談關(guān)于指針作為參數(shù)并改變它的值的問題

    這篇文章介紹了關(guān)于指針作為參數(shù)并改變它的值的問題,有需要的朋友可以參考一下
    2013-10-10
  • c++代碼各種注釋示例詳解

    c++代碼各種注釋示例詳解

    大家好,本篇文章主要講的是c++代碼各種注釋示例詳解,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • C++學(xué)習貝葉斯分類器實現(xiàn)手寫數(shù)字識別示例解析

    C++學(xué)習貝葉斯分類器實現(xiàn)手寫數(shù)字識別示例解析

    這篇文章主要介紹了在C++學(xué)習中如何采用貝葉斯分類器來實現(xiàn)手寫數(shù)字識別的示例及解析有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-10-10
  • c語言string.h頭文件中所有函數(shù)示例詳解

    c語言string.h頭文件中所有函數(shù)示例詳解

    這篇文章詳細介紹了C語言標準庫中的字符串和內(nèi)存操作函數(shù),以str開頭的字符串處理函數(shù)和以mem開頭的內(nèi)存處理函數(shù),每種函數(shù)都有詳細的原型、功能描述和示例代碼,需要的朋友可以參考下
    2024-11-11
  • opencv實現(xiàn)圖像傾斜校正

    opencv實現(xiàn)圖像傾斜校正

    這篇文章主要為大家詳細介紹了opencv實現(xiàn)圖像傾斜校正,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • C++中4種類型轉(zhuǎn)換的方法分享

    C++中4種類型轉(zhuǎn)換的方法分享

    這篇文章主要為大家詳細介紹了C++中4種類型轉(zhuǎn)換的方法,文中的示例代碼講解詳細,對我們學(xué)習C++有一定的幫助,感興趣的可以了解一下
    2023-04-04
  • C++標準模板庫map的常用操作

    C++標準模板庫map的常用操作

    今天小編就為大家分享一篇關(guān)于C++標準模板庫map的常用操作,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • 用C語言如何打印一個等腰三角形

    用C語言如何打印一個等腰三角形

    這篇文章主要介紹了用C語言如何打印一個等腰三角形,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C++函數(shù)參數(shù)匹配規(guī)則示例小結(jié)

    C++函數(shù)參數(shù)匹配規(guī)則示例小結(jié)

    這篇文章主要介紹了C++函數(shù)參數(shù)匹配規(guī)則,本文通過示例代碼給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • C++實現(xiàn)商品管理程序

    C++實現(xiàn)商品管理程序

    這篇文章主要為大家詳細介紹了C++實現(xiàn)商品管理程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12

最新評論

潮安县| 全南县| 电白县| 常山县| 波密县| 河间市| 福安市| 崇左市| 仙桃市| 化州市| 枣强县| 阳朔县| 清水河县| 威远县| 新绛县| 盖州市| 綦江县| 丰顺县| 张家口市| 名山县| 株洲市| 翁牛特旗| 出国| 黑河市| 普陀区| 杨浦区| 武鸣县| 蛟河市| 汉源县| 特克斯县| 宣化县| 冀州市| 运城市| 宜城市| 白水县| 霞浦县| 井研县| 琼结县| 南阳市| 定南县| 大安市|