Qt開發 | Qt創建線程 | Qt并發-QtConcurrent

文章目錄

  • 一、Qt創建線程的三種方法
  • 二、Qt并發:QtConcurrent介紹
  • 三、QtConcurrent run參數說明
  • 四、獲取QtConcurrent的返回值
  • 五、C++其他線程技術介紹

一、Qt創建線程的三種方法

??以下是Qt創建線程的三種方法:

  • 方法一:派生于QThread

    派生于QThread,這是Qt創建線程最常用的方法。線程類中重寫虛函數void QThread::run();,在run()函數中寫具體內容,外部通過start()調用,即可執行線程體run()

    注意:派生于QThread的類,構造函數屬于主線程,run函數屬于子線程,可以通過打印線程id來判斷

    示例:

    VS中創建Qt控制臺項目

    MyThread.h

    #pragma once#include <QThread>class MyThread : public QThread
    {
    public:MyThread();void run()override;
    };
    

    MyThread.cpp

    #include "MyThread.h"
    #include <QDebug>MyThread::MyThread()
    {qDebug() << "MyThread construct id =" << QThread::currentThreadId;
    }void MyThread::run()
    {qDebug() << "MyThread run id =" << QThread::currentThreadId;int index = 0;while (1){qDebug() << index++;QThread::msleep(500);}
    }
    

    main.cpp

    #include <QtCore/QCoreApplication>
    #include <QDebug>
    #include "MyThread.h"int main(int argc, char *argv[])
    {QCoreApplication a(argc, argv);qDebug() << "main thread id = " << QThread::currentThreadId;MyThread th;th.start();qDebug() << "main thread end!";return a.exec();
    }
    

    運行結果

    main thread id =  0x78272815
    MyThread construct id = 0x78272815
    main thread end!
    MyThread run id = 0x78272815
    0
    1
    2
    3
    4
    5
    6
    ...
    
  • 方法二:派生于QRunnable

    派生于QRunnable,重寫run()方法,在run()方法里處理其他任務,調用時需要借助Qt線程池

    注意:這種新建線程的方法的最大缺點是:不能使用Qt信號槽機制,因為QRunnable不是繼承自QObject。但是這種方法的好處是:可以讓QThreadPool來管理線程,QThreadPool會自動清理我們新建的QRunnable對象。

    示例:

    MyRunnable.h

    #pragma once#include <QRunnable>class MyRunnable : public QRunnable
    {
    public:MyRunnable();void run()override;
    };
    

    MyRunnable.cpp

    #include "MyRunnable.h"
    #include <QThread>
    #include <QDebug>MyRunnable::MyRunnable()
    {qDebug() << "MyRunnable construct id =" << QThread::currentThreadId;
    }void MyRunnable::run()
    {qDebug() << "MyRunnable run id =" << QThread::currentThreadId;
    }
    

    main.cpp

    #include <QtCore/QCoreApplication>
    #include <QDebug>
    #include <QThreadPool>
    #include "MyThread.h"
    #include "MyRunnable.h"int main(int argc, char *argv[])
    {QCoreApplication a(argc, argv);qDebug() << "main thread id = " << QThread::currentThreadId;//MyThread th;//th.start();MyRunnable* th = new MyRunnable();QThreadPool::globalInstance()->start(th);qDebug() << "main thread end!";return a.exec();
    }
    

    運行結果

    main thread id =  0x78272815
    MyRunnable construct id = 0x78272815
    main thread end!
    MyRunnable run id = 0x78272815
    
  • 方法三:moveToThread

    派生于QObject,使用moveToThread方法將任何QObject派生類的實例移動到另一個線程。將QThread對象作為私有成員,在構造函數里moveToThread,然后啟動線程

    QThread *thread = new QThread;
    this->moveToThread(thread);
    thread->start();
    

    示例:

    MyObject.h

    #pragma once
    #include <qobject.h>
    #include <QThread>class MyObject : public QObject
    {Q_OBJECT
    public:MyObject();public slots:void process();private:QThread m_pTh;
    };
    

    MyObject.cpp

    #include "MyObject.h"
    #include <QDebug>MyObject::MyObject()
    {this->moveToThread(&m_pTh);m_pTh.start();qDebug() << "MyObject construct id = " << QThread::currentThreadId();
    }void MyObject::process()
    {qDebug() << "MyObject process id = " << QThread::currentThreadId();int index = 0;while (1){qDebug() << index++;QThread::msleep(300);}
    }
    

    ch7_1_mtt.h

    #pragma once#include <QtWidgets/QWidget>
    #include "ui_ch7_1_mtt.h"
    #include "MyObject.h"class ch7_1_mtt : public QWidget
    {Q_OBJECTpublic:ch7_1_mtt(QWidget *parent = nullptr);~ch7_1_mtt();public slots:void on_pushButton_clicked();signals:void sig_pro();private:Ui::ch7_1_mttClass ui;MyObject* m_pObj;
    };
    

    ch7_1_mtt.cpp

    #include "ch7_1_mtt.h"
    #include <QDebug>ch7_1_mtt::ch7_1_mtt(QWidget *parent): QWidget(parent)
    {ui.setupUi(this);qDebug() << "main construct id = " << QThread::currentThreadId();m_pObj = new MyObject();connect(this, &ch7_1_mtt::sig_pro, m_pObj, &MyObject::process);
    }ch7_1_mtt::~ch7_1_mtt()
    {}void ch7_1_mtt::on_pushButton_clicked()
    {//通過信號槽方式調用,相當于在子線程中運行;若直接調用process()函數,則相當于在主線程中運行emit sig_pro();
    }
    

    在槽函數中進行耗時操作可以使用線程,在子線程中進行耗時操作

    main.cpp

    #include "ch7_1_mtt.h"
    #include <QtWidgets/QApplication>int main(int argc, char *argv[])
    {QApplication a(argc, argv);ch7_1_mtt w;w.show();return a.exec();
    }
    

    運行結果

    main construct id = 0x52dc
    MyObject construct id =  0x52dc
    MyObject process id =  0x78272815
    0
    1
    2
    3
    4
    5
    6
    7
    

二、Qt并發:QtConcurrent介紹

??QtConcurrent是Qt框架中的一個模塊,用于簡化并發和多線程編程。它提供了一種高效的方式來執行并行任務,而無需直接處理線程的復雜性。QtConcurrent基于模板和函數式編程,使得編寫并發代碼更加簡潔和易于理解。以下是QtConcurrent的一些關鍵特性:

  • 基于模板的并行算法:QtConcurrent提供了一系列的并行算法,如QtConcurrent::map()QtConcurrent::filter()QtConcurrent::reduce()等,它們可以并行地對數據集執行操作。
  • 基于Qt的線程池管理:QtConcurrent使用Qt的線程池來管理線程,這意味著開發者不需要手動創建和銷毀線程,從而簡化了線程管理。
  • 信號和槽的集成:QtConcurrent可以與Qt的信號和槽機制無縫集成,使得并行任務的結果可以很容易地通過信號傳遞給其他對象。
  • 懶加載和任務取消:QtConcurrent支持懶加載,即任務只有在實際需要結果時才開始執行。此外,它還支持取消正在執行的任務。
  • 異常處理:QtConcurrent可以處理并行執行過程中拋出的異常,確保程序的健壯性。
  • 無阻塞的等待:QtConcurrent提供了一種機制來等待并行任務的完成,而不會阻塞調用線程。
Header:
#include <QtConcurrent> 
qmake:
QT += concurrent

QtConcurrent基本用法:

??QtConcurrent::run這行代碼的作用是啟動ch72_concurrent類的timeTask成員函數在單獨的線程中異步執行,并且返回一個QFuture<int>對象,用于跟蹤執行的狀態和獲取返回值。

QFuture<int> ft = QtConcurrent::run(this, &ch72_concurrent::timeTask);while (!ft.isFinished())
{//用于處理事件隊列中的事件的。這個函數可以確保應用程序界面保持響應狀態,即使在執行長時間運行的任務時//當future未完成時,讓cpu去做別的事QApplication::processEvents(QEventLoop::AllEvents, 30); 
}

示例:

xx.h

#pragma once#include <QtWidgets/QWidget>
#include "ui_ch72_concurrent.h"class ch72_concurrent : public QWidget
{Q_OBJECTpublic:ch72_concurrent(QWidget *parent = nullptr);~ch72_concurrent();int timeTask();private slots:void on_pushButton_clicked();private:Ui::ch72_concurrentClass ui;
};

xx.cpp

#include "ch72_concurrent.h"
#include <QThread>
#include <QDebug>
#include <QtConcurrent>
#include <QFuture>ch72_concurrent::ch72_concurrent(QWidget *parent): QWidget(parent)
{ui.setupUi(this);
}ch72_concurrent::~ch72_concurrent()
{}int ch72_concurrent::timeTask()
{int num = 0;for (int i = 0; i < 1000000; i++){num++;qDebug() << num;}return num;
}void ch72_concurrent::on_pushButton_clicked()
{//timeTask();QFuture<int> ft = QtConcurrent::run(this, &ch72_concurrent::timeTask);while (!ft.isFinished()){//用于處理事件隊列中的事件的。這個函數可以確保應用程序界面保持響應狀態,即使在執行長時間運行的任務時QApplication::processEvents(QEventLoop::AllEvents, 30); }
}

main.cpp

#include "ch72_concurrent.h"
#include <QtWidgets/QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);ch72_concurrent w;w.show();return a.exec();
}

三、QtConcurrent run參數說明

??QtConcurrent run函數參數,可以是全局函數,也可以是類成員函數。

  • 類成員函數做run參數

    int ch73_concurrent::timeTask(int num1, int num2)
    {//int num = 0;for (int i = 0; i < 1000000; i++){num1++;num2++;qDebug() << num1;qDebug() << num2;}return num1 + num2;
    }void ch73_concurrent::on_pushButton_clicked()
    {//timeTask();int num1 = 0;int num2 = 0;QFuture<int> ft = QtConcurrent::run(this, &ch73_concurrent::timeTask, num1, num2);while (!ft.isFinished()){QApplication::processEvents(QEventLoop::AllEvents, 30);}
    }
    
  • 全局函數做run參數

    static int gTimeTask(int num1, int num2)
    {//int num = 0;for (int i = 0; i < 1000000; i++){num1++;num2++;qDebug() << num1;qDebug() << num2;}return num1 + num2;
    }void ch73_concurrent::on_pushButton_clicked()
    {//timeTask();int num1 = 0;int num2 = 0;//QFuture<int> ft = QtConcurrent::run(this, &ch73_concurrent::timeTask, num1, num2);QFuture<int> ft = QtConcurrent::run(gTimeTask, num1, num2);while (!ft.isFinished()){QApplication::processEvents(QEventLoop::AllEvents, 30);}
    }
    

四、獲取QtConcurrent的返回值

??獲取QtConcurrent的結果,需要使用QFutureWatcher類,鏈接它的信號finished,然后給watcher設置future,當監控到future執行結束后,可以獲取它的執行結果,調用的是result()函數。

int ch74::timeTask(int& num1, int& num2)
{for (int i = 0; i < 1000; i++){num1++;num2++;qDebug() << num1;qDebug() << num2;}return num1 + num2;
}void ch74::on_pushButton_clicked()
{int num1 = 0;int num2 = 0;QFutureWatcher<int>* fw = new QFutureWatcher<int>;connect(fw, &QFutureWatcher<int>::finished, [&]{qDebug() << "QFutureWatcher finished";qDebug() << "result = " << fw->result();});QFuture<int> ft = QtConcurrent::run(this, &ch74::timeTask, num1, num2);fw->setFuture(ft);while (!ft.isFinished()){QApplication::processEvents(QEventLoop::AllEvents, 30);}
}

五、C++其他線程技術介紹

  • pthread:linux線程
    • 這是POSIX線程庫,主要用于Unix-like系統,如Linux和macOS。
    • 提供了豐富的線程創建和管理功能,包括互斥鎖、條件變量等同步機制。
  • win32-pthread,obs的線程全部使用了win32-pthread
    • 這是一個在Windows平臺上模擬POSIX線程庫的庫。
    • OBS(Open Broadcaster Software)等應用程序使用這個庫來實現跨平臺的線程功能。
  • windows thread類
    • Windows API提供了自己的線程類,如Win32 Thread,用于創建和管理線程。
    • 這些線程類通常與Windows特定的功能緊密結合,如窗口消息處理。
  • MFC thread類
    • MFC(Microsoft Foundation Classes)是一套C++庫,用于Windows應用程序開發。
    • MFC提供了自己的線程類,例如CWinThread,用于簡化線程的創建和管理。
  • boost
    • Boost庫是一個廣泛使用的C++庫集合,其中包含了線程庫。
    • Boost.Thread提供了跨平臺的線程支持,包括線程創建、同步等。
  • std::thread(推薦使用這個,基于語言級別的跨平臺C++線程)
    • C++11標準引入了std::thread,這是語言級別的線程支持。
    • 推薦使用std::thread,因為它提供了跨平臺的線程支持,并且與C++標準庫緊密集成。
    • std::thread簡化了線程的創建和管理,同時提供了豐富的同步機制,如std::mutexstd::condition_variable等。

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

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

相關文章

理解算法復雜度:空間復雜度詳解

引言 在計算機科學中&#xff0c;算法復雜度是衡量算法效率的重要指標。時間復雜度和空間復雜度是算法復雜度的兩個主要方面。在這篇博客中&#xff0c;我們將深入探討空間復雜度&#xff0c;了解其定義、常見類型以及如何進行分析。空間復雜度是衡量算法在執行過程中所需內存…

ceph mgr [errno 39] RBD image has snapshots (error deleting image from trash)

ceph mgr 報錯 debug 2024-07-08T09:25:56.512+0000 7f9c63bd2700 0 [rbd_support INFO root] execute_task: task={"sequence": 3, "id": "260b9fee-d567-4301-b7eb-b1fe1b037413", "message": "Removing image replicapool/8…

昇思25天學習打卡營第19天|Diffusion擴散模型

學AI還能贏獎品&#xff1f;每天30分鐘&#xff0c;25天打通AI任督二脈 (qq.com) Diffusion擴散模型 本文基于Hugging Face&#xff1a;The Annotated Diffusion Model一文翻譯遷移而來&#xff0c;同時參考了由淺入深了解Diffusion Model一文。 本教程在Jupyter Notebook上成…

python庫 - missingno

missingno 是一個用于可視化和分析數據集中缺失值的 Python 庫。它提供了一系列簡單而強大的工具&#xff0c;幫助用戶直觀地理解數據中的缺失模式&#xff0c;從而更好地進行數據清洗和預處理。missingno 庫特別適用于數據分析和數據科學項目&#xff0c;尤其是在處理缺失數據…

昇思MindSpore學習筆記5-02生成式--RNN實現情感分類

摘要&#xff1a; 記錄MindSpore AI框架使用RNN網絡對自然語言進行情感分類的過程、步驟和方法。 包括環境準備、下載數據集、數據集加載和預處理、構建模型、模型訓練、模型測試等。 一、概念 情感分類。 RNN網絡模型 實現效果&#xff1a; 輸入: This film is terrible 正…

放大鏡案例

放大鏡 <!DOCTYPE html> <html lang"zh-cn"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>商品放大鏡</title><link rel&qu…

如何使用allure生成測試報告

第一步下載安裝JDK1.8&#xff0c;參考鏈接JDK1.8下載、安裝和環境配置教程-CSDN博客 第二步配置allure環境&#xff0c;參考鏈接allure的安裝和使用(windows環境)_allure windows-CSDN博客 第三步&#xff1a; 第四步&#xff1a; pytest 查看目前運行的測試用例有無錯誤 …

如何使用 pytorch 創建一個神經網絡

我已發布在&#xff1a;如何使用 pytorch 創建一個神經網絡 SapientialM.Github.io 構建神經網絡 1 導入所需包 import os import torch from torch import nn from torch.utils.data import DataLoader from torchvision import datasets, transforms2 檢查GPU是否可用 dev…

ffmpeg濾鏡創建過程

1、創建一個濾鏡圖 AVFilterGraph *filter_graph avfilter_graph_alloc(); 2、創建濾鏡的輸入和輸出 AVFilterInOut *inputs avfilter_inout_alloc(); AVFilterInOut *outputs avfilter_inout_alloc(); 3、每個濾鏡創建上下文 AVFilterContext *filter1_ctx avfilter_…

Yolov10訓練,轉化onnx,推理

yolov10對于大目標的效果好&#xff0c;小目標不好 一、如果你訓練過yolov5&#xff0c;yolov8&#xff0c;的話那么你可以直接用之前的環境就行 目錄 一、如果你訓練過yolov5&#xff0c;yolov8&#xff0c;的話那么你可以直接用之前的環境就行 二、配置好后就可以配置文件…

android webview 遠程調試

打開遠程調試選項 MainActivity super.onCreate(savedInstanceState);// enable Cordova apps to be started in the backgroundBundle extras getIntent().getExtras();if (extras ! null && extras.getBoolean("cdvStartInBackground", false)) {moveT…

前端JS特效第24集:jquery css3實現瀑布流照片墻特效

jquery css3實現瀑布流照片墻特效&#xff0c;先來看看效果&#xff1a; 部分核心的代碼如下(全部代碼在文章末尾)&#xff1a; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8" /> <title>jquerycss3實現瀑…

Nginx:負載均衡小專題

運維專題 Nginx&#xff1a;負載均衡小專題 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/…

在Conda環境中高效使用Kubernetes:跨平臺容器化實踐指南

摘要 Conda 是一個流行的跨平臺包和環境管理器&#xff0c;廣泛用于Python社區。而 Kubernetes 是一個開源的容器編排系統&#xff0c;用于自動化部署、擴展和管理容器化應用程序。本文將探討如何在 Conda 環境中使用 Kubernetes&#xff0c;包括設置 Conda 環境、容器化應用程…

【專項刷題】— 位運算

常見類型介紹&#xff1a; & &#xff1a;有 0 就是 0 | &#xff1a;有 1 就是 1 ^ &#xff1a;相同為 0 &#xff0c;相異為 1 或者 無進位相加給定一個數確定它的二進制位的第x個數是0還是1&#xff1a;將一個數的二進制的第x位改成1&#xff1a;將一個數的二進制的第x…

Windows10/11家庭版開啟Hyper-V虛擬機功能詳解

Hyper-V是微軟的一款虛擬機軟件&#xff0c;可以使我們在一臺Windows PC上&#xff0c;在虛擬環境下同時運行多個互相之間完全隔離的操作系統&#xff0c;這就實現了在Windows環境下運行Linux以及其他OS的可能性。和第三方虛擬機軟件&#xff0c;如VMware等相比&#xff0c;Hyp…

Linux應用編程IO基礎

Linux應用編程基本IO操作 一、main 函數1、main 函數寫法之無傳參2、main 函數寫法之有傳參 二、open 打開文件三、write 寫文件四、read 讀文件五、close 關閉文件六、 lseek七、 返回錯誤處理與 errno7.1 strerror 函數7.2 perror 函數 八、 exit、_exit、_Exit8.1_exit()和_…

零基礎自學爬蟲技術該從哪里入手?

零基礎學習Python并不一定是困難的&#xff0c;這主要取決于個人的學習方法、投入的時間以及學習目標的設定。Python是一門相對容易入門的編程語言&#xff0c;它有著簡潔的語法、豐富的庫和廣泛的應用領域&#xff08;如數據分析、Web開發、人工智能等&#xff09;&#xff0c…

大模型知識問答: 文本分塊要點總結

節前&#xff0c;我們組織了一場算法崗技術&面試討論會&#xff0c;邀請了一些互聯網大廠朋友、今年參加社招和校招面試的同學。 針對大模型技術趨勢、算法項目落地經驗分享、新手如何入門算法崗、該如何準備面試攻略、面試常考點等熱門話題進行了深入的討論。 總結鏈接如…

C++ 信號量和鎖的區別

網上關于信號量和鎖的區別&#xff0c;寫的比較官方晦澀難懂&#xff0c;對于這個知識點吸收難&#xff0c;通過示例&#xff0c;我們看到信號量&#xff0c;可以控制同一時刻的線程數量&#xff0c;就算同時開啟很多線程&#xff0c;依然可以的達到線程數可控 #include <i…