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

Qt線(xiàn)程QtConcurrent模塊的使用

 更新時(shí)間:2026年01月05日 10:23:59   作者:Larry_Yanan  
QtConcurrent是Qt特有的一個(gè)用于實(shí)現(xiàn)并發(fā)任務(wù)的模塊,本文主要介紹了Qt線(xiàn)程QtConcurrent模塊的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

在傳統(tǒng) Qt 多線(xiàn)程開(kāi)發(fā)中,我們常通過(guò)繼承 QThread 或使用 moveToThread 來(lái)實(shí)現(xiàn)后臺(tái)任務(wù)。但這種方式需要手動(dòng)管理線(xiàn)程生命周期、信號(hào)槽連接、對(duì)象所有權(quán)等,樣板代碼多、易出錯(cuò)。
而 Qt Concurrent 提供了一種更高層次的抽象:你只關(guān)心“做什么”,不關(guān)心“在哪做”。它基于線(xiàn)程池自動(dòng)調(diào)度任務(wù),極大簡(jiǎn)化了并發(fā)編程。
QtConcurrent是Qt特有的一個(gè)用于實(shí)現(xiàn)并發(fā)任務(wù)的模塊,提供了一組基于任務(wù)(task-based)而非線(xiàn)程(thread-based)的并發(fā)API。它底層使用 QThreadPool + QRunnable 實(shí)現(xiàn),自動(dòng)管理線(xiàn)程池,你無(wú)需手動(dòng)創(chuàng)建/銷(xiāo)毀線(xiàn)程。如果有一個(gè)或多個(gè)短期簡(jiǎn)單任務(wù)會(huì)造成主線(xiàn)程的阻塞,又覺(jué)得為了他單獨(dú)設(shè)計(jì)一個(gè)任務(wù)類(lèi)再移動(dòng)到子線(xiàn)程太過(guò)繁瑣,我們可以使用QtConcurrent。

一、QtConcurrent::run()

QtConcurrent::run()是最簡(jiǎn)單的單任務(wù)線(xiàn)程實(shí)現(xiàn)。在寫(xiě)具體代碼之前,我們需要先在pro文件中添加相應(yīng)模塊:

QT += concurrent

然后添加頭文件:

#include <QtConcurrent>

和之前一樣,通過(guò)點(diǎn)擊界面按鈕觸發(fā)測(cè)試代碼:

int compute(int a, int b) {
    QThread::msleep(500);
    return a + b;
}

void MainWindow::on_btn_thread_start_3_clicked()
{
    static int a = 10, b = 20;
    a++;
    b++;

    // 1?? 啟動(dòng)異步任務(wù)
    QFuture<int> future = QtConcurrent::run(compute, a, b);

    // 2?? 創(chuàng)建 watcher 監(jiān)聽(tīng)完成事件
    QFutureWatcher<int> *watcher = new QFutureWatcher<int>(this);
    
    // 3?? 連接 finished 信號(hào)(在主線(xiàn)程觸發(fā)?。?
    connect(watcher, &QFutureWatcher<int>::finished, this, [watcher]() {
        qDebug() << "Result:" << watcher->result();
        watcher->deleteLater(); // 自動(dòng)清理內(nèi)存
    });

    // 4?? 將 future 綁定到 watcher
    watcher->setFuture(future);
}

啟動(dòng)任務(wù)的時(shí)候,需要傳遞任務(wù)函數(shù)和參數(shù):

QFuture<int> future = QtConcurrent::run(compute, a, b);

返回值是第一個(gè)可監(jiān)聽(tīng)的對(duì)象,代表一個(gè)未來(lái)會(huì)得到的的結(jié)果。
這一步是同步不阻塞的,隨后我們要馬上對(duì)future對(duì)象進(jìn)行觀察。注意QFuture本身是沒(méi)有信號(hào)的,因此無(wú)法使用信號(hào)槽。所以我們要單獨(dú)設(shè)置一個(gè)QFutureWatcher來(lái)進(jìn)行觀察,最后綁定future。代碼比較簡(jiǎn)單,就不詳細(xì)說(shuō)了。注意watcher要在最終的槽函數(shù)中析構(gòu)哦。
可以看到compute任務(wù)函數(shù)中,除了簡(jiǎn)單的加法運(yùn)算之外,還特意做了線(xiàn)程延時(shí)。
最后,我們運(yùn)行代碼:

每次點(diǎn)擊都會(huì)疊加運(yùn)算,并且界面完全不阻塞。
這種寫(xiě)法特別適合做簡(jiǎn)單但有可能造成阻塞的任務(wù),相比于特意重載QThread或使用moveToThread,簡(jiǎn)直是清爽多了。(以前工作不太懂,所以也沒(méi)用過(guò),實(shí)在可惜。)
結(jié)合我過(guò)往的開(kāi)發(fā)經(jīng)驗(yàn),說(shuō)幾個(gè)可能的應(yīng)用場(chǎng)景:
(1)批量加載:本地有多個(gè)圖片文件需要加載讀取,甚至還要進(jìn)行尺寸壓縮
(2)多點(diǎn)繪圖:QImage中需要繪制多線(xiàn)段,這常常伴隨鼠標(biāo)滑動(dòng)繪圖,為了不阻塞主線(xiàn)程影響流暢度,應(yīng)當(dāng)考慮線(xiàn)程。

二、QtConcurrent::mapped()

除此之外,QtConcurrent也提供了其他的方式,比如QtConcurrent::mapped()(并行轉(zhuǎn)換)和 QtConcurrent::filtered()(并行過(guò)濾)。
我嘗試了mapped的方式,它是一種批量的線(xiàn)程實(shí)現(xiàn),在某些場(chǎng)合下挺實(shí)用的。
接下來(lái),嘗試一下圖片的批量加載,并進(jìn)行灰度轉(zhuǎn)換,最后彈窗顯示出來(lái)。
代碼如下:

QImage convertToGrayscale(const QString& filePath)
{
    // 模擬阻塞
    QThread::msleep(2000);
    QImage img(filePath);
    if (img.isNull()) {
        qWarning() << "Failed to load:" << filePath;
        return QImage(); // 返回空?qǐng)D
    }
    // 轉(zhuǎn)為黑白(灰度)
    return img.convertToFormat(QImage::Format_Grayscale8);
}

void MainWindow::on_btn_thread_start_3_1_clicked()
{
    // 1. 選擇多個(gè)圖片文件(最多10個(gè))
    QStringList filePaths = QFileDialog::getOpenFileNames(
        this,
        "選擇圖片(最多10張)",
        QDir::homePath(),
        "Images (*.png *.jpg *.jpeg *.bmp *.gif)"
        );

    if (filePaths.isEmpty()) {
        return;
    }

    if (filePaths.size() > 10) {
        QMessageBox::warning(this, "警告", "最多只能選擇10張圖片!");
        filePaths = filePaths.mid(0, 10);
    }

    // 2. 禁用按鈕,防止重復(fù)點(diǎn)擊
    // m_convertButton->setEnabled(false);

    // 3. 啟動(dòng)并發(fā)轉(zhuǎn)換
    QFuture<QImage> future = QtConcurrent::mapped(filePaths, convertToGrayscale);

    // 4. 設(shè)置 watcher 監(jiān)聽(tīng)完成
    if (!m_watcher) {
        m_watcher = new QFutureWatcher<QImage>(this);
        connect(m_watcher, &QFutureWatcher<QImage>::finished,
                this, &MainWindow::onConversionFinished);
    }
    m_watcher->setFuture(future);
}

void MainWindow::onConversionFinished()
{
    // 5. 獲取所有結(jié)果(順序與輸入 filePaths 一致)
    QList<QImage> results = m_watcher->future().results();

    // 6. 為每張有效圖片彈窗顯示
    int validCount = 0;
    for (int i = 0; i < results.size(); ++i) {
        if (!results[i].isNull()) {
            QString title = QString("結(jié)果 %1").arg(++validCount);
            showImageInDialog(results[i], title);
        }
    }

    // 7. 恢復(fù)按鈕
    // m_convertButton->setEnabled(true);

    if (validCount == 0) {
        QMessageBox::information(this, "提示", "沒(méi)有成功加載任何圖片。");
    }
}

void MainWindow::showImageInDialog(const QImage &img, const QString &title)
{
    QDialog* dialog = new QDialog(this);
    dialog->setAttribute(Qt::WA_DeleteOnClose); // 關(guān)閉時(shí)自動(dòng) delete
    dialog->setWindowTitle(title);
    dialog->resize(600, 400);

    QLabel* label = new QLabel(dialog);
    label->setPixmap(QPixmap::fromImage(img).scaled(
        dialog->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
    label->setAlignment(Qt::AlignCenter);

    QVBoxLayout* layout = new QVBoxLayout(dialog);
    layout->addWidget(label);
    dialog->setLayout(layout);

    dialog->show();
}

我們關(guān)注一下這里:

QFuture<QImage> future = QtConcurrent::mapped(filePaths, convertToGrayscale);

先是參數(shù),后是接口,這一點(diǎn)與run有區(qū)別。接口的參數(shù)是QString,但傳遞的參數(shù)卻是QStringList,也就是說(shuō)qt會(huì)自動(dòng)幫我們適應(yīng),處理批量線(xiàn)程??梢钥吹椒祷刂狄琅f是QFuture,它的參數(shù)是QImage,而不是批量的QList<QImage>,這一點(diǎn)要注意哦。
同樣的任務(wù)函數(shù)做了一點(diǎn)延時(shí)模擬阻塞,順便轉(zhuǎn)換了下灰度。
最后就是完成的槽函數(shù),這代表所有任務(wù)都已經(jīng)完成。

QList<QImage> results = m_watcher->future().results();

返回值可以通過(guò)results接口獲取。之后就是常規(guī)的彈窗,就不多解釋了。
運(yùn)行代碼,查看結(jié)果:

在延時(shí)的兩秒時(shí)間內(nèi),界面完全沒(méi)有被阻塞,隨后三個(gè)彈窗一起彈出來(lái),效果還是很好的。

三、總結(jié)

有關(guān)QtConcurrent的其他接口測(cè)試就先忽略了。光是run和mapped兩種方式,我就已經(jīng)覺(jué)得非常實(shí)用了。

以下是QtConcurrent和QThread+Worker的對(duì)比:

可以看到,QtConcurrent更適合用作一次性的計(jì)算任務(wù),特別是簡(jiǎn)單一次性的并行任務(wù)。如果是需要長(zhǎng)期運(yùn)行的任務(wù),如while循環(huán)獲取,還是采用QThread+Worker比較好。

到此這篇關(guān)于Qt線(xiàn)程QtConcurrent模塊的使用的文章就介紹到這了,更多相關(guān)Qt QtConcurrent模塊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++函數(shù)對(duì)象詳解附帶實(shí)例

    C++函數(shù)對(duì)象詳解附帶實(shí)例

    這篇文章主要介紹了C++函數(shù)對(duì)象詳解附帶實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • C/C++實(shí)現(xiàn)的MD5哈希校驗(yàn)的示例代碼

    C/C++實(shí)現(xiàn)的MD5哈希校驗(yàn)的示例代碼

    MD5算法是一種廣泛使用的 Hash 算法,常用于確保信息傳輸?shù)耐暾耘c一致性,本文主要介紹了C/C++實(shí)現(xiàn)的MD5哈希校驗(yàn)的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • C語(yǔ)言編寫(xiě)洗牌發(fā)牌程序

    C語(yǔ)言編寫(xiě)洗牌發(fā)牌程序

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言編寫(xiě)洗牌發(fā)牌程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • 簡(jiǎn)單談?wù)凜++ 頭文件系列之(algorithm)

    簡(jiǎn)單談?wù)凜++ 頭文件系列之(algorithm)

    <algorithm>是c++特有的STL模板的算法頭文件 包含了一些特定的算法函數(shù) 包括sort(),stable_sort(),partical_sort(),nth_element()等常用的算法函數(shù)
    2017-02-02
  • C++ Primer 第一部分基本語(yǔ)言

    C++ Primer 第一部分基本語(yǔ)言

    這篇文章主要介紹了C++ Primer 第一部分基本語(yǔ)言的相關(guān)資料,需要的朋友可以參考下
    2014-02-02
  • C++模擬實(shí)現(xiàn)List迭代器詳解

    C++模擬實(shí)現(xiàn)List迭代器詳解

    list不同于其他容器,他是一個(gè)鏈表,物理地址并不連續(xù)。所以在實(shí)現(xiàn)list類(lèi)的迭代器的時(shí)候,需要將迭代器單獨(dú)封裝到一個(gè)類(lèi)里,因?yàn)樾枰剌d很多操作符來(lái)跟其他容器的迭代器使用達(dá)成一致
    2022-04-04
  • 在vs2017上配置AppGameKit庫(kù)的圖文教程

    在vs2017上配置AppGameKit庫(kù)的圖文教程

    這篇文章主要介紹了在vs2017上配置AppGameKit庫(kù)的教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • C語(yǔ)言之預(yù)處理命令的深入講解

    C語(yǔ)言之預(yù)處理命令的深入講解

    這篇文章主要給大家介紹了關(guān)于C語(yǔ)言之預(yù)處理命令的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • C 二分查找 遞歸與非遞歸的實(shí)現(xiàn)代碼

    C 二分查找 遞歸與非遞歸的實(shí)現(xiàn)代碼

    C 二分查找 遞歸與非遞歸的實(shí)現(xiàn)代碼,需要的朋友可以參考一下
    2013-03-03
  • C++實(shí)現(xiàn)學(xué)校人員管理系統(tǒng)

    C++實(shí)現(xiàn)學(xué)校人員管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)學(xué)校人員管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03

最新評(píng)論

神农架林区| 镇远县| 沙坪坝区| 兴安县| 皮山县| 通榆县| 吕梁市| 克拉玛依市| 安庆市| 红桥区| 长岛县| 丰原市| 达日县| 井冈山市| 密云县| 京山县| 关岭| 阿瓦提县| 郓城县| 库尔勒市| 晋州市| 东丽区| 吉木乃县| 汽车| 田林县| 岐山县| 大英县| 贵南县| 青阳县| 黄梅县| 德化县| 武强县| 明星| 平江县| 盐城市| 宜兴市| 高雄市| 宜兰市| 新干县| 大理市| 象州县|