Qt多線程技術【線程池】:QRunnable 和 QThreadPool

在現代軟件開發中,尤其是在處理大量并發任務時,線程池技術是一種高效的解決方案。線程池不僅能提高程序的性能,還能有效管理線程的生命周期,避免頻繁的線程創建和銷毀所帶來的性能損失。本文將以Qt中的 QThreadPoolQRunnable 為核心,通過具體代碼實例來講解線程池技術的應用及其工作原理。


線程池概述

線程池(ThreadPool)是一種用于管理和復用線程的技術。在多線程編程中,我們經常需要處理大量的小任務,頻繁地創建和銷毀線程會帶來性能上的開銷。線程池通過預先創建一定數量的線程來處理任務,任務完成后線程會被返回到線程池中等待下一次使用,從而避免了創建新線程的開銷。

線程池可以根據任務量動態地調整線程的數量,保持一定數量的線程處于空閑狀態,并且通過合理調度任務來提高并發執行的效率。

Qt為我們提供了 QThreadPoolQRunnable 類來輕松實現線程池機制。通過這兩個類,開發者可以更簡便地管理線程,并將復雜的并發任務拆分為小的可執行任務交給線程池去處理。


QRunnable 類解析

在Qt中,QRunnable 是一個用于表示線程池任務的基類。它并不像 QThread 那樣直接創建和管理線程,而是通過將任務提交給 QThreadPool 來實現多線程工作。QRunnable 的主要作用是將任務封裝成可執行的單元,每個 QRunnable 對象都會有一個 run() 方法,該方法定義了任務執行的具體操作。

QRunnable 提供了以下幾個重要方法:

  • run(): 這是 QRunnable 類中的純虛函數,用于定義任務的執行邏輯。開發者需要重寫此方法,來描述任務的行為。
  • setAutoDelete(): 該方法允許在任務完成后自動刪除該任務對象。這在使用 QThreadPool 時非常有用,可以避免內存泄漏。
  • setPriority(): 可以設置任務的優先級,QRunnable 支持通過此方法將任務分配不同的優先級。
QThreadPool 類解析

QThreadPool 類是Qt中的線程池實現類,負責管理并調度多個線程。QThreadPool 提供了線程池的創建、線程的管理和任務的調度等功能。開發者可以通過 QThreadPool 提交多個任務,并且線程池會自動分配線程來執行這些任務。

QThreadPool 提供了以下幾個常用的方法:

  • globalInstance(): 返回一個全局的線程池實例,通常用于獲取默認的線程池。
  • start(QRunnable *runnable): 向線程池中提交任務,線程池會根據當前線程的空閑情況分配線程來執行該任務。
  • waitForDone(): 阻塞等待線程池中的所有任務執行完成。這在某些場景下非常有用,例如需要確保所有任務都完成后再繼續執行下一步操作。
  • setMaxThreadCount(): 設置線程池中最大線程數,防止系統資源過度消耗。

線程池技術的優勢

  1. 減少開銷:頻繁創建和銷毀線程會帶來額外的開銷。線程池通過復用線程,避免了這種性能浪費。
  2. 線程管理自動化:開發者不需要手動管理線程的創建、銷毀等操作,線程池自動處理線程的生命周期。
  3. 避免資源浪費:通過動態調整線程池的大小,可以根據負載動態增加或減少線程數量,避免線程資源過度消耗。
  4. 高效并行執行:線程池可以同時執行多個任務,特別適用于需要處理大量短小任務的場景。

代碼實現:使用 QThreadPoolQRunnable

為了更好地理解線程池的應用,我們提供了一個簡單的Qt程序示例,展示如何使用 QThreadPoolQRunnable 類來處理并發任務。

頭文件:worker.h
#ifndef WORKER_H
#define WORKER_H#include <QRunnable>  // 用于創建線程任務
#include <QString>
#include <QDebug>
#include <QThread>#define tc(a) QString::fromLocal8Bit(a)// 工作任務類,繼承自QRunnable
class Worker : public QRunnable
{
public:Worker(const QString &taskName, int retryCount = 3);  // 構造函數,傳入任務名稱和重試次數void run() override;  // 線程池中的任務執行邏輯private:QString m_taskName;  // 任務名稱int m_retryCount;    // 任務失敗時的最大重試次數bool executeTask();  // 執行任務的模擬方法
};#endif // WORKER_H
源文件:worker.cpp
#include "worker.h"
#include <QThread>
#include <QRandomGenerator>// 構造函數,初始化任務名稱和重試次數,設置任務自動刪除
Worker::Worker(const QString &taskName, int retryCount): m_taskName(taskName), m_retryCount(retryCount)
{setAutoDelete(true);  // 設置自動刪除任務
}// 重寫run函數,線程池中的任務執行邏輯
void Worker::run()
{int attempt = 0;bool success = false;// 嘗試執行任務,直到達到重試次數或任務成功while (attempt < m_retryCount && !success) {attempt++;qDebug() << tc("嘗試執行任務:") << m_taskName << tc("嘗試次數:") << attempt;success = executeTask();  // 執行任務if (!success) {qDebug() << tc("任務失敗,重試中:") << m_taskName;QThread::sleep(2);  // 模擬任務失敗后的等待}}if (success) {qDebug() << tc("任務完成:") << m_taskName;} else {qDebug() << tc("任務失敗,超過最大重試次數:") << m_taskName;}
}// 模擬任務執行的邏輯,50%概率失敗
bool Worker::executeTask()
{// 使用隨機數模擬任務失敗return QRandomGenerator::global()->bounded(2) == 0;
}
主程序文件:main.cpp
#include <QCoreApplication>
#include <QThreadPool>
#include <QDebug>
#include "worker.h"#define tc(a) QString::fromLocal8Bit(a)int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 獲取全局線程池實例QThreadPool *threadPool = QThreadPool::globalInstance();// 設置最大線程數為4threadPool->setMaxThreadCount(4);// 創建多個任務并添加到線程池Worker *task1 = new Worker(tc("任務 1"));Worker *task2 = new Worker(tc("任務 2"));Worker *task3 = new Worker(tc("任務 3"));Worker *task4 = new Worker(tc("任務 4"), 2);  // 設置任務4最大重試次數為2次Worker *task5 = new Worker(tc("任務 5"));// 向線程池中添加任務threadPool->start(task1);threadPool->start(task2);threadPool->start(task3);threadPool->start(task4);threadPool->start(task5);// 等待線程池中的任務完成threadPool->waitForDone();return a.exec();
}
嘗試執行任務: 任務 1 嘗試次數: 1
任務完成: 任務 1
嘗試執行任務: 任務 2 嘗試次數: 1
任務完成: 任務 2
嘗試執行任務: 任務 3 嘗試次數: 1
任務完成: 任務 3
嘗試執行任務: 任務 4 嘗試次數: 1
任務失敗,重試中: 任務 4
嘗試執行任務: 任務 4 嘗試次數: 2
任務完成: 任務 4
嘗試執行任務: 任務 5 嘗試次數: 1
任務完成: 任務 5

代碼講解
  1. QRunnableQThreadPool 的結合使用

    • 我們通過繼承 QRunnable 創建了一個 Worker 類來封裝任務,每個 Worker 實例表示一個任務。
    • 任務的執行邏輯被定義在 run() 方法中,而任務的失敗重試機制由 executeTask() 方法模擬。
    • main() 函數中,我們通過 QThreadPool::globalInstance() 獲取全局線程池實例,設置最大線程數為4,并將多個任務提交到線程池執行。
  2. 自動刪除任務

    • setAutoDelete(true) 確保任務在執行完成后自動被刪除,這有效防止了內存泄漏。
  3. 任務執行過程

    • 每個任務都會隨機失敗,模擬實際應用中的網絡請求或數據庫操作失敗的場景,最多重試3次。
    • QThread::sleep(2) 模擬任務執行時的延遲,使得任務的執行過程更加真實。
  4. 線程池管理

    • 線程池會根據當前可用線程的數量來調度任務,如果有空閑線程,任務會立刻執行;如果線程池的線程數已經達到最大值,新的任務會排隊等待。

總結

線程池技術能夠減少線程創建和銷毀的開銷,通過任務調度和線程復用提高了程序的性能和并發處理能力。QRunnable 提供了靈活的任務管理方式,QThreadPool 則負責高效的線程管理與任務調度。

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

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

相關文章

DOM讓JavaScript可以對文檔中的標簽、屬性、內容等進行 訪增刪改 操作

示例 HTML 文檔 首先&#xff0c;我們有一個簡單的 HTML 文件 index.html&#xff0c;內容如下&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widt…

218.子結構判斷

class Solution {/*** 判斷樹 B 是否是樹 A 的子結構* param A 樹 A 的根節點* param B 樹 B 的根節點* return 如果 B 是 A 的子結構&#xff0c;返回 true&#xff1b;否則返回 false*/public boolean isSubStructure(TreeNode A, TreeNode B) {// 如果樹 B 為空&#xff0c;…

【DuodooBMS】基于Odoo的開源制造執行系統——以開源之力,驅動智能制造

以用戶為中心的開放式智造平臺 DuodooMES的設計始終圍繞“用戶可編程、生態可生長”的核心思想&#xff0c;打破傳統工業軟件的封閉性&#xff0c;讓制造企業真正成為系統的“主人”&#xff1a; 1. 用戶可編程&#xff1a;生產流程由你定義 界面可配置&#xff1a;無需代碼即…

Unity使用iTextSharp導出PDF-02基礎結構及設置中文字體

基礎結構 1.創建一個Document對象 2.使用PdfWriter創建PDF文檔 3.打開文檔 4.添加內容&#xff0c;調用文檔Add方法添加內容時&#xff0c;內容寫入到輸出流中 5.關閉文檔 using UnityEngine; using iTextSharp.text; using System.IO; using iTextSharp.text.pdf; using Sys…

Navicat導入海量Excel數據到數據庫(簡易介紹)

目錄 前言正文 前言 此處主要作為科普帖進行記錄 原先Java處理海量數據的導入時&#xff0c;由于接口超時&#xff0c;數據處理不過來&#xff0c;后續轉為Navicat Navicat 是一款功能強大的數據庫管理工具&#xff0c;支持多種數據庫系統&#xff08;如 MySQL、PostgreSQL、…

文化財經t8優質短線期貨交易量化模型源碼

// 參數設置 BOLL_PERIOD : 20; // 布林帶周期 RSI_PERIOD : 14; // RSI 周期 OVERSOLD : 30; // 超賣線 OVERBOUGHT : 70; // 超買線 // 計算布林帶 MID : MA(CLOSE, BOLL_PERIOD); UPPER : MID 2 * STD(CLOSE, BOLL_PERIOD); LOWER : MID - 2 * STD(CLOSE,…

[AI]Mac本地部署Deepseek R1模型 — — 保姆級教程

[AI]Mac本地部署DeepSeek R1模型 — — 保姆級教程 DeepSeek R1是中國AI初創公司深度求索&#xff08;DeepSeek&#xff09;推出大模型DeepSeek-R1。 作為一款開源模型&#xff0c;R1在數學、代碼、自然語言推理等任務上的性能能夠比肩OpenAI o1模型正式版&#xff0c;并采用MI…

【UE5】PeerStream像素流部署

視頻教程 https://www.bilibili.com/video/BV1GhiuecEpK?spm_id_from333.788.videopod.sections&vd_source02dd8acc3a83a728e375ff61f1ebe725步驟 下載PeerStream代碼 代碼結構和項目如圖 github地址:https://github.com/inveta/PeerStreamEnterprise下載node node 對應…

老牌系統工具箱,現在還能打!

今天給大家分享一款超實用的電腦軟硬件檢測工具&#xff0c;雖然它是一款比較“資深”的軟件&#xff0c;但依然非常好用&#xff0c;完全能滿足我們的日常需求。 電腦軟硬件維護檢測工具 功能強大易用 這款軟件非常貼心&#xff0c;完全不需要安裝&#xff0c;直接打開就能用…

java商城解決方案

數字化時代&#xff0c;電子商務已成為企業拓展市場的重要渠道。對于想要建立在線商店的企業來說&#xff0c;選擇正確的技術堆棧至關重要。 Java作為一種成熟且廣泛使用的編程語言&#xff0c;為構建購物中心提供了強大的功能和靈活性。 商城Java源碼&#xff1a;商城開發的核…

軟件的生命周期和需求

什么是軟件的生命周期? 定義(描述) --> 創建 --> 使用 --> 銷毀 (這一整個過程就是事物的生命周期) 生命周期 那么軟件的生命周期又分為哪些呢? 一共分為十步: 可行性研究: 通過分析軟件開發要求,確定軟件項目的性質、目標和規模,得出可行性研究報告,如果可行性研…

QGIS如何下載高程數據

一、準備工作 安裝QGIS軟件 訪問QGIS官網下載最新版本,選擇適合操作系統的安裝包(如Windows 64位)完成安裝。建議使用3.28及以上版本以獲得完整功能支持。 注冊數據平臺賬號 NASA EarthData賬號:訪問EarthData登錄頁面注冊,用于SRTM數據下載。地理空間數據云賬號:訪問www…

【linux學習指南】線程同步與互斥

文章目錄 &#x1f4dd;線程互斥&#x1f320; 庫函數strncpy&#x1f309;進程線程間的互斥相關背景概念&#x1f309;互斥量mutex &#x1f320;線程同步&#x1f309;條件變量&#x1f309;同步概念與競態條件&#x1f309; 條件變量函數 &#x1f6a9;總結 &#x1f4dd;線…

MySQL索引優化,性能飆升的秘密!

0.前言 假設你經營一家電商平臺&#xff0c;某天用戶突然投訴商品搜索加載時間超過10秒。技術團隊緊急排查&#xff0c;發現一條原本執行0.1秒的查詢語句&#xff0c;在百萬級數據量下竟變成了全表掃描。這時&#xff0c;數據庫索引猶如深夜急診室里的救命儀器——它的存在與否…

基于STM32、HAL庫、HS12864(ST7920,并行接口)C語言程序設計

1、hs12864.h頭文件: #ifndef __HS12864_H #define __HS12864_H #ifdef __cplusplus extern "C" {#endif #include "stm32l4xx_hal.h" // 控制線定義 - 根據實際硬件修改 #define HS12864_RS_GPIO_PORT GPIOC #define HS12864_RS_PIN GPIO_PI…

【C語言】C語言 實踐課題選題系統(源碼+報告+數據文件)【獨一無二】

&#x1f449;博__主&#x1f448;&#xff1a;米碼收割機 &#x1f449;技__能&#x1f448;&#xff1a;C/Python語言 &#x1f449;專__注&#x1f448;&#xff1a;專注主流機器人、人工智能等相關領域的開發、測試技術。 系C語言 實踐課題選題系統&#xff08;源碼報告數據…

基于SpringBoot的“高考志愿智能推薦系統”的設計與實現(源碼+數據庫+文檔+PPT)

基于SpringBoot的“高考志愿智能推薦系統”的設計與實現&#xff08;源碼數據庫文檔PPT) 開發語言&#xff1a;Java 數據庫&#xff1a;MySQL 技術&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系統展示 系統總體結構圖 系統首頁界面 系統注冊頁…

React 低代碼項目:組件設計

React 低代碼項目&#xff1a;組件設計 Date: February 6, 2025 React表單組件 **目標&#xff1a;**使用 Ant Design 表單組件&#xff0c;開發登錄、注冊、搜索功能 內容&#xff1a; 使用 React 表單組件、受控組件使用 Ant Design 表單組件使用 表單組件的校驗和錯誤提…

深入剖析 Vue 的響應式原理:構建高效 Web 應用的基石

深入剖析 Vue 的響應式原理&#xff1a;構建高效 Web 應用的基石 在前端開發的廣闊天地里&#xff0c;Vue.js 憑借其簡潔易用的特性和強大的功能&#xff0c;成為眾多開發者的心頭好。其中&#xff0c;響應式原理作為 Vue 的核心亮點之一&#xff0c;讓數據與視圖之間實現了高…

QCustomplot庫運用

最近需要用到這個庫顯示數據&#xff0c;需要在一個曲線圖4個Y軸共用一個X軸&#xff0c;并且做游標&#xff0c;跟隨鼠標移動&#xff0c;并且實時反饋數據到表格中。記錄一下程序。 customPlot new QCustomPlot(this); customPlot->setBackground(QBrush(QColor(204,204,…