【C++/Qt shared_ptr 與 線程池】合作使用案例

以下是一個結合 std::shared_ptr 和 Qt 線程池(QThreadPool)的完整案例,展示了如何在多線程任務中安全管理資源,避免內存泄漏。


案例場景

  • 任務目標:在后臺線程中處理一個耗時的圖像檢測任務,任務對象通過 std::shared_ptr 管理。
  • 關鍵需求
    • 確保任務對象在任務完成后自動釋放。
    • 支持跨線程信號槽通信,傳遞處理結果。
    • 避免線程池與智能指針所有權沖突。

完整代碼

1. 自定義任務類(繼承自 QRunnable
// MyTask.h
#pragma once
#include <QRunnable>
#include <QObject>
#include <memory>
#include <QImage>class MyTask : public QObject, public QRunnable
{Q_OBJECT
public:MyTask(const QImage& inputImage);// 任務執行入口void run() override;// 設置任務完成后回調(通過信號)void setResultCallback(std::function<void(const QImage&)> callback);signals:// 任務完成信號,傳遞處理后的圖像void taskFinished(const QImage& result);private:QImage m_inputImage;std::function<void(const QImage&)> m_callback;
};
// MyTask.cpp
#include "MyTask.h"
#include <QDebug>MyTask::MyTask(const QImage& inputImage) : m_inputImage(inputImage)
{// 禁用 QRunnable 的自動刪除setAutoDelete(false);
}void MyTask::run()
{qDebug() << "Task started in thread:" << QThread::currentThreadId();// 模擬耗時操作(例如圖像處理)QImage processedImage = m_inputImage.mirrored(true, false);// 發送完成信號(跨線程)emit taskFinished(processedImage);// 或者調用回調函數if (m_callback) {m_callback(processedImage);}
}void MyTask::setResultCallback(std::function<void(const QImage&)> callback)
{m_callback = callback;
}

2. 主窗口類(使用線程池和 shared_ptr
// MainWindow.h
#pragma once
#include <QMainWindow>
#include <QThreadPool>
#include <memory>class MainWindow : public QMainWindow
{Q_OBJECT
public:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:// 處理任務完成信號void handleTaskFinished(const QImage& result);private:QThreadPool* m_threadPool;
};
// MainWindow.cpp
#include "MainWindow.h"
#include "MyTask.h"
#include <QPushButton>
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), m_threadPool(new QThreadPool(this))
{// 設置線程池最大線程數m_threadPool->setMaxThreadCount(4);// 創建一個測試按鈕,點擊后提交任務QPushButton* btn = new QPushButton("Run Task", this);connect(btn, &QPushButton::clicked, [this]() {// 1. 創建任務對象并用 shared_ptr 管理QImage inputImage(800, 600, QImage::Format_RGB32);inputImage.fill(Qt::green);std::shared_ptr<MyTask> task = std::make_shared<MyTask>(inputImage);// 2. 連接任務完成信號到主線程的槽connect(task.get(), &MyTask::taskFinished, this, &MainWindow::handleTaskFinished, Qt::QueuedConnection); // 確保跨線程安全// 3. 提交任務到線程池(傳遞原始指針,但所有權由 shared_ptr 控制)m_threadPool->start(task.get());// 4. 使用 Lambda 捕獲 shared_ptr,確保任務完成后釋放資源task->setResultCallback([task](const QImage& result) {qDebug() << "Task callback executed. Ref count:" << task.use_count();});});
}void MainWindow::handleTaskFinished(const QImage& result)
{qDebug() << "Task finished. Result size:" << result.size();
}MainWindow::~MainWindow()
{// 等待所有任務完成m_threadPool->waitForDone();
}

3. 主函數
// main.cpp
#include "MainWindow.h"
#include <QApplication>int main(int argc char *argv[])
{QApplication a(argc, argv);// 注冊自定義類型(若需要傳遞復雜類型)// qRegisterMetaType<MyData>("MyData");MainWindow w;w.show();return a.exec();
}

關鍵機制解釋

  1. 禁用自動刪除

    setAutoDelete(false); // 在 MyTask 構造函數中
    
    • 阻止 QThreadPool 自動刪除任務對象,避免與 shared_ptr 沖突。
  2. 通過 shared_ptr 管理生命周期

    std::shared_ptr<MyTask> task = std::make_shared<MyTask>(inputImage);
    
    • shared_ptr 確保任務對象在最后一個引用消失時自動釋放。
  3. 信號槽跨線程通信

    connect(task.get(), &MyTask::taskFinished, this, &MainWindow::handleTaskFinished, Qt::QueuedConnection);
    
    • 使用 Qt::QueuedConnection 確保信號跨線程安全傳遞。
  4. Lambda 捕獲 shared_ptr

    task->setResultCallback([task](const QImage& result) {qDebug() << "Ref count:" << task.use_count();
    });
    
    • Lambda 表達式捕獲 task 會遞增引用計數,確保任務執行期間對象存活。

運行流程

  1. 用戶點擊按鈕,創建任務并用 shared_ptr 管理。
  2. 任務被提交到線程池,線程池調用 run() 執行耗時操作。
  3. 任務完成后,發送 taskFinished 信號或調用回調。
  4. 主線程接收結果并處理。
  5. 當所有引用(shared_ptr)釋放后,任務對象自動銷毀。

注意事項

  1. 線程安全設計
    • 如果任務內部訪問共享數據,需使用 QMutexQReadWriteLock 保護。
  2. 避免循環引用
    • 如果任務對象持有指向主窗口的指針,需使用原始指針或 weak_ptr,避免 shared_ptr 循環引用導致內存泄漏。
  3. 性能優化
    • 如果頻繁創建任務,可復用任務對象或使用對象池減少內存分配開銷。

通過此案例,您可以安全地在 Qt 線程池中使用 std::shared_ptr,確保資源生命周期正確管理。

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

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

相關文章

【Unity】 HTFramework框架(六十五)ScrollList滾動數據列表

更新日期&#xff1a;2025年5月16日。 Github 倉庫&#xff1a;https://github.com/SaiTingHu/HTFramework Gitee 倉庫&#xff1a;https://gitee.com/SaiTingHu/HTFramework 索引 一、ScrollList滾動數據列表二、使用ScrollList1.快捷創建ScrollList2.ScrollList的屬性3.自定義…

經典案例 | 筑基與躍升:解碼制造企業產供銷協同難題

引言 制造企業如何在投產初期突破管理瓶頸&#xff0c;實現高效運營&#xff1f;G公司作為某大型集團的新建子公司&#xff0c;面對產供銷流程缺失、跨部門協同低效等難題&#xff0c;選擇與AMT企源合作開展流程優化。 項目通過端到端流程體系搭建、標準化操作規范制定及長效管…

【Python 操作 MySQL 數據庫】

在 Python 中操作 MySQL 數據庫主要通過 pymysql 或 mysql-connector-python 庫實現。以下是完整的技術指南&#xff0c;包含連接管理、CRUD 操作和最佳實踐&#xff1a; 一、環境準備 1. 安裝驅動庫 pip install pymysql # 推薦&#xff08;純Python實現&#xff0…

記錄vsCode連接gitee并實現項目拉取和上傳

標題 在 VSCode 中上傳代碼到 Gitee 倉庫 要在 VSCode 中將代碼上傳到 Gitee (碼云) 倉庫&#xff0c;你可以按照以下步驟操作&#xff1a; 準備工作 確保已安裝 Git確保已安裝 VSCode擁有 Gitee 賬號并創建了倉庫 可以參考該文章的部分&#xff1a;idea實現與gitee連接 操…

【信息系統項目管理師】第6章:項目管理概論 - 31個經典題目及詳解

更多內容請見: 備考信息系統項目管理師-專欄介紹和目錄 文章目錄 第一節 PMBOK的發展【第1題】【第2題】【第3題】【第4題】【第5題】【第6題】第二節 項目基本要素【第1題】【第2題】【第3題】【第4題】【第5題】【第6題】【第7題】【第8題】【第9題】【第10題】第三節 項目經…

簡單介紹C++中線性代數運算庫Eigen

Eigen 是一個高性能的 C 模板庫&#xff0c;專注于線性代數、矩陣和向量運算&#xff0c;廣泛應用于科學計算、機器學習和計算機視覺等領域。以下是對 Eigen 庫的詳細介紹&#xff1a; 1. 概述 核心功能&#xff1a;支持矩陣、向量運算&#xff0c;包括基本算術、矩陣分解&…

生產級編排AI工作流套件:Flyte全面使用指南 — Core concepts Launch plans

生產級編排AI工作流套件&#xff1a;Flyte全面使用指南 — Core concepts Launch plans Flyte 是一個開源編排器&#xff0c;用于構建生產級數據和機器學習流水線。它以 Kubernetes 作為底層平臺&#xff0c;注重可擴展性和可重復性。借助 Flyte&#xff0c;用戶團隊可以使用 P…

Python 之類型注解

類型注解允許開發者顯式地聲明變量、函數參數和返回值的類型。但是加不加注解對于程序的運行沒任何影響&#xff08;是非強制的&#xff0c;且類型注解不影響運行時行為&#xff09;&#xff0c;屬于 有了挺好&#xff0c;沒有也行。但是大型項目按照規范添加注解的話&#xff…

rocketmq并發消費

netty的handler 在netty的網絡模型中&#xff0c;在想bootstrap設置handler時&#xff0c; 都是在等待 事件 的到來&#xff0c;才會被調用的方法&#xff0c;都是被動的&#xff0c; 服務端等待 request 的到來&#xff0c;進行read, 然后主動調用writeAndFlush寫出去。 客戶…

React 播客專欄 Vol.9|React + TypeScript 項目該怎么起步?從 CRA 到配置全流程

&#x1f44b; 歡迎回到《前端達人 React 播客書單》第 9 期&#xff08;正文內容為學習筆記摘要&#xff0c;音頻內容是詳細的解讀&#xff0c;方便你理解&#xff09;&#xff0c;請點擊下方收聽 你是不是常在網上看到 .tsx 項目、Babel、Webpack、tsconfig、Vite、CRA、ESL…

【PmHub后端篇】PmHub中基于自定義注解和AOP的服務接口鑒權與內部認證實現

1 引言 在現代軟件開發中&#xff0c;尤其是在微服務架構下&#xff0c;服務接口的鑒權和內部認證是保障系統安全的重要環節。本文將詳細介紹PmHub中如何利用自定義注解和AOP&#xff08;面向切面編程&#xff09;實現服務接口的鑒權和內部認證&#xff0c;所涉及的技術知識點…

芯片測試之X-ray測試

原理&#xff1a; X-ray是利用陰極射線管產生高能量電子與金屬靶撞擊&#xff0c;在撞擊過程中&#xff0c;因電子突然減速&#xff0c;其損失的動能會以X-Ray形式放出。而對于樣品無法以外觀方式觀測的位置&#xff0c;利用X-Ray穿透不同密度物質后其光強度的變化&#xff0c;…

QBasic 一款古老的編程語言在現代學習中的價值(附程序)

QBasic&#xff08;Quick Beginner’s All-purpose Symbolic Instruction Code&#xff09;是微軟公司于 1991 年推出的一款簡單易學的編程語言&#xff0c;作為BASIC語言的變種&#xff0c;它曾廣泛應用于教育領域和初學者編程入門。盡管在當今Python、Java等現代編程語言主導…

【八股戰神篇】Java高頻基礎面試題

1 面向對象編程有哪些特性&#xff1f; 面向對象編程&#xff08;Object-Oriented Programming&#xff0c;簡稱 OOP&#xff09;是一種以對象為核心的編程范式&#xff0c;它通過模擬現實世界中的事物及其關系來組織代碼。OOP 具有三大核心特性&#xff1a;封裝、繼承、多態。…

科學養生指南:解鎖健康生活新方式

在快節奏的現代生活中&#xff0c;健康養生成為人們關注的焦點。想要擁有良好的身體狀態&#xff0c;無需依賴復雜的傳統理論&#xff0c;通過科學的生活方式&#xff0c;就能輕松實現養生目標。? 規律運動是健康的基石。每周進行 150 分鐘以上的中等強度有氧運動&#xff0c…

OpenCV閾值處理完全指南:從基礎到高級應用

引言 閾值處理是圖像處理中最基礎、最常用的技術之一&#xff0c;它能夠將灰度圖像轉換為二值圖像&#xff0c;為后續的圖像分析和處理奠定基礎。本文將全面介紹OpenCV中的各種閾值處理方法&#xff0c;包括原理講解、代碼實現和實際應用場景。 一、什么是閾值處理&#xff1…

Java8到24新特性整理

本文整理了 Java 8 至 Java 24 各版本的新特性&#xff0c;內容包括每個版本的新增功能分類&#xff08;如語法增強、性能優化、工具支持等&#xff09;、詳細的代碼示例&#xff0c;并結合官方文檔資料&#xff0c;分析每項特性的應用場景及優缺點。Java 8 發布于 2014 年&…

輪詢仲裁器

參考視頻 https://www.bilibili.com/video/BV1VQ4y1w7Rr/?spm_id_from333.337.search-card.all.click&vd_sourceaedd69dc9740e91cdd85c0dfaf25304b 算法原理

Armijo rule

非精線搜索步長規則Armijo規則&Goldstein規則&Wolfe規則_armijo rule-CSDN博客 [原創]用“人話”解釋不精確線搜索中的Armijo-Goldstein準則及Wolfe-Powell準則 – 編碼無悔 / Intent & Focused

力扣HOT100之二叉樹:102. 二叉樹的層序遍歷

這道題太簡單了&#xff0c;相當于基礎的模板題&#xff0c;但凡涉及到層序遍歷一定會用到隊列來實現&#xff0c;其他的倒沒啥好說的&#xff0c;用兩層while循環來層序遍歷&#xff0c;外層while循環用于控制訪問二叉樹的每一層&#xff0c;而內層while循環則負責收割每一層的…