1. Qt多線程開發

目錄

  • 方法1.繼承QThread
    • 使用案例
    • 總結
  • 方法2.將qobject對象moveToThread(官方推薦)
    • 使用案例
    • 總結
  • 方法3.QRunnable + QThreadPool
    • 使用案例
    • 總結
  • 方法4.快速線程QtConcurrent+QFutureWatcher
    • 使用案例
    • 總結
  • 代碼下載

方法1.繼承QThread

需要實現QThread的抽象函數run

#ifndef WORKERTHREAD_H
#define WORKERTHREAD_H#include <QObject>
#include <QThread>
#include <QDebug>class WorkerThread : public QThread
{Q_OBJECT
public:explicit WorkerThread(QObject *parent = nullptr);void func1();protected:virtual void run();signals:
};#endif // WORKERTHREAD_H#include "workerthread.h"WorkerThread::WorkerThread(QObject *parent): QThread{parent}
{}void WorkerThread::func1()
{qDebug()<< __FUNCTION__<< QThread::currentThread();
}void WorkerThread::run()
{qDebug()<< __FUNCTION__<< QThread::currentThread();
}

使用案例

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);qDebug()<< "主線程:" << QThread::currentThread();wt = new WorkerThread(this);wt->start();//執行WorkerThread的run在子線程中wt->func1();    //主線程connect(ui->pushButton,&QPushButton::clicked,wt,&WorkerThread::func1); //主線程}Widget::~Widget()
{delete ui;
}

總結

run函數是在子線程中執行的
其成員函數func1
a)直接調用的方式是在創建對象的線程(主線程)中執行的
b)信號槽連接的方式也是在創建對象的線程(主線程)中執行的

直接調用接口,如果包含了run線程中使用的變量可能就會導致數據競爭
此時就得考慮加鎖
如果run線程中獲取到了鎖,主線程調用WorkerThread的接口會導致阻塞,界面卡頓=
使用場景,不需要進行線程間數據交互

方法2.將qobject對象moveToThread(官方推薦)

#ifndef WORKER_H
#define WORKER_H#include <QObject>class Worker : public QObject
{Q_OBJECT
public:explicit Worker(QObject *parent = nullptr);~Worker();void func1();signals:
};#endif // WORKER_H
#include "worker.h"
#include <QThread>
#include <QDebug>Worker::Worker(QObject *parent): QObject{parent}
{}Worker::~Worker()
{
qDebug()<< __FUNCTION__ << QThread::currentThread();
}void Worker::func1()
{qDebug()<< __FUNCTION__ << QThread::currentThread();
}

使用案例

#ifndef FORM_H
#define FORM_H#include <QWidget>
#include <QThread>
#include <QDebug>#include "worker.h"namespace Ui {
class Form;
}class Form : public QWidget
{Q_OBJECTpublic:explicit Form(QWidget *parent = nullptr);~Form();
signals:void closeThread();private:Ui::Form *ui;
};#endif // FORM_H
#include "form.h"
#include "ui_form.h"Form::Form(QWidget *parent): QWidget(parent), ui(new Ui::Form)
{ui->setupUi(this);//根據親和性,不應設置為其他線程的成員對象QThread *th = new QThread();Worker *worker = new Worker();qDebug()<< "主線程:" << QThread::currentThread();worker->moveToThread(th);connect(th,&QThread::finished,worker,&Worker::deleteLater);connect(th,&QThread::finished,worker,&QThread::deleteLater);th->start();    //啟動子線程worker->func1();    //錯誤行為connect(ui->pushButton,&QPushButton::clicked,worker,&Worker::func1); //正確線程間通信connect(this,&Form::closeThread,th,&QThread::quit); //關閉線程
}Form::~Form()
{delete ui;emit closeThread();}

總結

使用場景: 線程之間頻繁交互的時候(官方推薦)

①禁止行為:禁止直接調用子線程對象接口或者修改數據
因為這會導致跨線程訪問問題,可能引發數據競爭、死鎖或程序崩潰。
應該通過信號槽連接進行線程間通信。

②獨立的事件循環
子線程開啟會產生一個獨立的事件循環,此時異步線程信號請求會在此次統一處理
不會對發起請求的線程阻塞;

③Qt 的父子對象與線程規則?
?規則 1?:所有 QObject 父子對象必須位于同一線程。
?規則 2?:調用 moveToThread() 會改變對象的線程親和性(Thread Affinity)。
?沖突點?:如果將一個已移動到子線程的 QObject 設置為另一個線程中對象的子對象,Qt 會觸發斷言崩潰(如 QObject: Cannot create children for a parent that is in a different thread)。
簡單點說既是;A線程中的對象不應該成為B線程的父對象或者子對象

方法3.QRunnable + QThreadPool

#ifndef WORKERTASK_H
#define WORKERTASK_H#include <QRunnable>class WorkerTask : public QRunnable
{
public:WorkerTask();~WorkerTask();
protected:virtual void run();
};#endif // WORKERTASK_H
#include "workertask.h"
#include <QThread>
#include <QDebug>WorkerTask::WorkerTask() {setAutoDelete(true);
}WorkerTask::~WorkerTask()
{
qDebug()<< __FUNCTION__<< QThread::currentThread();
}void WorkerTask::run()
{
qDebug()<< __FUNCTION__<< QThread::currentThread();
}

使用案例

#ifndef FORM1_H
#define FORM1_H#include <QWidget>
#include <QThread>
#include <QDebug>namespace Ui {
class Form1;
}class Form1 : public QWidget
{Q_OBJECTpublic:explicit Form1(QWidget *parent = nullptr);~Form1();private:Ui::Form1 *ui;
};#endif // FORM1_H
#include "form1.h"
#include "ui_form1.h"
#include "workertask.h"
#include <QThreadPool>Form1::Form1(QWidget *parent): QWidget(parent), ui(new Ui::Form1)
{ui->setupUi(this);qDebug()<< "主線程:" << QThread::currentThread();QThreadPool::globalInstance()->start(new WorkerTask());}Form1::~Form1()
{delete ui;
}

總結

場景:適合短生命周期的任務
用完就釋放

方法4.快速線程QtConcurrent+QFutureWatcher

其他線程都得創建一堆的對象,管理對象的創建與釋放生命周期,
但是QtConcurrent不用,使用QtConcurrent我們可以快速開啟一個線程

使用案例

#include "form2.h"
#include "ui_form2.h"
#include <QDebug>
#include <QThread>
#include <QtConcurrent>
#include <QtConcurrent/QtConcurrentMap>Form2::Form2(QWidget *parent): QWidget(parent), ui(new Ui::Form2)
{ui->setupUi(this);qDebug()<< "主線程:" << QThread::currentThread();
}Form2::~Form2()
{delete ui;
}void Form2::on_pushButton_clicked()
{QList<int> list = {1, 2, 3, 4, 5};//通過map開啟多個線程執行, 如果使用for每個元素處理是耗時的,但是采用此法可以并行處理// QFuture<void> future = QtConcurrent::map(list, [](int &value) {//     value *= 2; // 將每個元素乘以2//     qDebug()<< __FUNCTION__ << QThread::currentThread();// });QFuture<int> future = QtConcurrent::run([]() -> int {// 計算并返回結果return 42;});qDebug()<< future.result(); //阻塞等待結構
}

綁定監聽器,全部執行完則發出fnish信號

QFutureWatcher<void> watcher;
connect(&watcher, &QFutureWatcher<void>::finished, this, []() {qDebug() << "圖像處理完成";
});watcher.setFuture(future);

總結

?避免修改共享數據?:盡量使用值傳遞而非引用傳遞
?使用輕量級函數?:并行執行的函數應該盡可能輕量
?合理設置線程池大小?:使用 QThreadPool::globalInstance()->setMaxThreadCount()
?處理異常?:確保并行函數不會拋出未捕獲的異常

代碼下載

鏈接: 下載

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

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

相關文章

ARM入門學習方法分享

首先認識什么是ARM?ARM公司簡介ARM是Advanced RISC Machines的縮寫&#xff0c;它是一家微處理器行業的知名企業&#xff0c;該企業設計了大量高性能、廉價、耗能低的RISC &#xff08;精簡指令集&#xff09;處理器。 1985年第一個ARM原型在英國劍橋誕生。公司的特點是只設計…

基于springboot的在線數碼商城/在線電子產品商品銷售系統的設計與實現

用戶&#xff1a;數碼產品&#xff0c;限時秒殺&#xff0c;種草分享&#xff0c;新品資訊&#xff0c;留言板&#xff0c;訂單管理&#xff0c;在線客服&#xff0c;購物車&#xff0c;個人中心管理員&#xff1a;個人中心&#xff0c;用戶管理&#xff0c;數碼分類管理&#…

Zookeeper學習專欄(十):核心流程剖析之服務啟動、請求處理與選舉協議

文章目錄前言一、服務端啟動流程1.1 啟動入口類&#xff1a;QuorumPeerMain1.2 集群模式啟動核心&#xff1a;runFromConfig1.3 QuorumPeer線程核心邏輯&#xff1a;run()1.4 關鍵子流程&#xff1a;數據恢復1.5 關鍵設計要點二、請求處理鏈&#xff08;責任鏈模式&#xff09;…

網絡基礎19--OSPF路由業務多區域

一、OSPF多區域必要性單區域問題&#xff1a;LSDB龐大 → 內存占用高&#xff0c;SPF計算開銷大LSA洪泛范圍廣 → 拓撲變化影響全域無法路由匯總 → 路由表膨脹&#xff0c;查找效率低2. 多區域優勢&#xff1a;1. 劃分區域&#xff1a;獨立LSDB&#xff0c;縮小數據庫規模2. 限…

MFC擴展庫BCGControlBar Pro v36.2新版亮點:圖形管理器等全新升級

BCGControlBar庫擁有500多個經過全面設計、測試和充分記錄的MFC擴展類。 我們的組件可以輕松地集成到您的應用程序中&#xff0c;并為您節省數百個開發和調試時間。 BCGControlBar專業版 v36.2已全新發布了&#xff0c;在這個版本中添加了一個新的擴展器控件、改進了網格和報表…

QT開發---網絡編程上

Qt Network 模塊Qt Network 模塊提供了豐富的類用于實現各種網絡通信功能&#xff0c;涵蓋 TCP、UDP、HTTP、FTP 等多種協議。 Qt 網絡類均為異步操作&#xff0c;通過信號槽處理結果&#xff0c;避免阻塞 UI 線程。在使用QT進行網絡編程之前&#xff0c;就必須在 CMakeLists.t…

[spring6: Mvc-函數式編程]-源碼解析

接口 ServerRequest public interface ServerRequest {HttpMethod method();URI uri();UriBuilder uriBuilder();default String path() {return requestPath().pathWithinApplication().value();}default RequestPath requestPath() {return ServletRequestPathUtils.getPar…

Linux DNS 服務器正反向解析

一、環境說明與準備工作 1.基礎信息 本次實驗用兩臺 Linux 主機&#xff0c;分別作為 DNS 服務端和客戶端&#xff0c;具體信息如下&#xff1a;服務端IP客戶端IP網址192.168.120.130192.168.120.128www.zy.com2.準備工作 關閉安全軟件&#xff1a;服務端和客戶端都要關閉防火墻…

歷史數據分析——中證旅游

中證旅游板塊走勢從月線級別來看2015年5月到2024年9月&#xff0c;月線上走出了一個震蕩中樞的月線級別下跌段&#xff1b;目前月線級別底部放巨量&#xff0c;總體還在底部震蕩&#xff0c;后續上漲的概率較大。從周線級別來看從2022年12月到2024年9月整體是下跌走勢&#xff…

OpHReda精準預測酶最佳PH

1.顯著改進&#xff1a;OpHReda通過檢索嵌入數據增強機制&#xff0c;顯著提高了酶最佳pH預測的準確性&#xff0c;相比現有方法提升了55%的F1分數。2.多尺度殘差輕注意力模塊&#xff1a;該模塊結合了殘差學習和多尺度特征提取&#xff0c;增強了模型對酶序列中殘差級信息的捕…

醫護行業在未來會被AI淘汰嗎?

隨著AI的迅速發展&#xff0c;似乎所有職業都有被AI替代的風險&#xff0c;那麼醫療領域作為一個高技術依賴性的行業&#xff0c;有機會被淘汰嗎?我們今天就來說說&#xff0c;幾乎不可能被AI淘汰的職業---護理。一) AI在護理中扮演的角色i.) 臨床工作支持1. 健康監測自動化即…

大語言模型加速技術之KV Cache

大語言模型加速技術之KV CacheWhy we need KV Cache &#xff1f;Self-Attention Without CacheSelf-Attention With CacheHuggingface 官方代碼實現Why we need KV Cache &#xff1f; 生成式generative模型的推理過程很有特點&#xff0c;我們給一個輸入文本&#xff0c;模型…

代碼隨想錄算法訓練營第五十三天|圖論part4

110.字符串接龍 題目鏈接&#xff1a;110. 字符串接龍文章講解&#xff1a;代碼隨想錄思路&#xff1a; 把每個字符串看成圖的一個節點。 轉換為求無權圖兩節點的的最短路徑。求最短路徑用bfs #include <string> #include <vector> #include <iostream> #i…

Java進階4:泛型、序列化和反序列化

Java泛型 Java泛型是JDK5引入的一個新的特性&#xff0c;泛型提供了編譯時的類型安全檢測機制&#xff0c;這個機制運行程序員在編譯的時候檢測到非法的類型。泛型的本質是參數化類型&#xff0c;也就是所操作的數據類型被指定為一個參數。 泛型方法 可以寫一個泛型方法&#x…

RAG實戰指南 Day 24:上下文構建與提示工程

【RAG實戰指南 Day 24】上下文構建與提示工程 文章內容 開篇 歡迎來到"RAG實戰指南"系列的第24天&#xff01;今天我們將深入探討RAG系統中至關重要的上下文構建與提示工程技術。在檢索增強生成系統中&#xff0c;如何有效地組織檢索到的文檔片段&#xff0c;并將…

AWD的攻擊和防御手段

一、AWD相關介紹 AWD&#xff08;Attack With Defence&#xff09;是 CTF 線下賽中最接近真實攻防場景、觀賞性和對抗性最強的賽制之一。 賽制本質 人人對抗&#xff1a;所有戰隊互為攻擊者與防守者。 零和記分&#xff1a;你拿到的每一分都是別人的失分&#xff0c;總積分恒…

泛微OA8前臺SQL注入

漏洞URL&#xff1a; http://106.15.190.147/js/hrm/getdata.jsp?cmdgetSelectAllId&sql***注入點 在getdata.jsp中&#xff0c;直接將request對象交給 weaver.hrm.common.AjaxManager.getData(HttpServletRequest, ServletContext) : 方法處理 在getData方法中&#xff0…

Android 藍牙學習

在Android中&#xff0c;進行藍牙設備掃描startDiscovery需要申請位置權限&#xff0c;但有的時候并不需要申請位置權限&#xff0c;就有了android:usesPermissionFlags"neverForLocation"&#xff0c;設置這個就不用申請位置權限來進行藍牙掃描。 android:usesPerm…

Earth靶機攻略

一.環境準備 1.1Earth靶機環境準備 首先將我們解壓好的的Earth.ova放入虛擬機里&#xff0c;并配置環境 將網絡連接換成NET連接 二.信息搜集 2.1ip搜集 2.1.1使用netdiscover命令掃描靶機的ip地址,發現地址為192.168.182.137 2.2端口掃描 2.2.1使用nmap工具對目標機進行端…

java8 List常用基本操作(去重,排序,轉換等)

參考簡述網址: java8 List 根據對象某個字段或多個字段去重、篩選、List轉Map、排序、分組、統計計數等等 list簡單方法示例如下&#xff1a; 一、先定義一個訂單對象&#xff08;Order&#xff09; public class Order {private Long id;private Long userId;private Strin…