【C++】C++異步編程四劍客:future、async、promise和packaged_task詳解

C++異步編程四劍客:future、async、promise和packaged_task詳解

1. 引言

1.1 異步編程的重要性

在現代C++編程中,異步操作是提高程序性能和響應能力的關鍵技術。它允許程序在等待耗時操作(如I/O、網絡請求或復雜計算)完成時繼續執行其他任務,從而充分利用系統資源。

1.2 C++中的異步工具

C++11引入了強大的異步編程支持,主要包括四個核心組件:

  • std::future/std::shared_future:異步結果獲取機制
  • std::async:簡單的異步任務啟動器
  • std::promise:異步結果提供者
  • std::packaged_task:可調用對象的包裝器

2. std::future:異步結果的橋梁

2.1 基本概念

std::future是一個模板類,它提供了一種訪問異步操作結果的機制。一個future對象通常與某個異步操作相關聯,并可以在未來某個時刻獲取該操作的結果。

2.2 主要功能

  • get():獲取異步操作的結果(如果結果未就緒,會阻塞當前線程)
  • wait():等待異步操作完成
  • wait_for()/wait_until():帶超時的等待

2.3 使用示例

#include <iostream>
#include <future>
#include <thread>int compute() {std::this_thread::sleep_for(std::chrono::seconds(2));return 42;
}int main() {std::future<int> result = std::async(std::launch::async, compute);std::cout << "Waiting for result..." << std::endl;std::cout << "Result: " << result.get() << std::endl;return 0;
}

3. std::async:簡單的異步任務啟動器

3.1 基本用法

std::async是啟動異步任務的最簡單方式,它返回一個std::future對象,通過該對象可以獲取異步任務的結果。

3.2 啟動策略

  • std::launch::async:強制在新線程中執行
  • std::launch::deferred:延遲執行,直到調用future.get()future.wait()
  • 默認策略:由實現決定

3.3 注意事項

  • 返回值std::future析構時會隱式等待
  • 不適合需要精細控制線程的場景

3.4 示例代碼

auto future1 = std::async(std::launch::async, []{// 耗時計算return calculateSomething();
});auto future2 = std::async(std::launch::deferred, []{// 這個任務不會立即執行return calculateSomethingElse();
});// 只有調用get()時才會執行future2的任務
auto result = future1.get() + future2.get();

4. std::promise:手動設置異步結果

4.1 核心概念

std::promise允許顯式地設置一個值或異常,這個值可以通過關聯的std::future對象獲取。

4.2 典型使用場景

  • 需要手動控制結果設置的時機
  • 跨線程回調
  • 復雜異步流程控制

4.3 基本用法

#include <iostream>
#include <future>
#include <thread>void compute(std::promise<int> prom) {try {int result = 42; // 模擬計算prom.set_value(result);} catch(...) {prom.set_exception(std::current_exception());}
}int main() {std::promise<int> prom;std::future<int> fut = prom.get_future();std::thread t(compute, std::move(prom));t.detach();std::cout << "Result: " << fut.get() << std::endl;return 0;
}

5. std::packaged_task:可調用對象的包裝器

5.1 基本概念

std::packaged_task包裝一個可調用對象(函數、lambda表達式、函數對象等),并允許異步獲取該調用的結果。

5.2 主要特點

  • 將任務與結果獲取分離
  • 可以像普通函數對象一樣被調用
  • 適合需要將任務傳遞給線程池的場景

5.3 使用示例

#include <iostream>
#include <future>
#include <thread>
#include <deque>std::deque<std::packaged_task<int()>> task_queue;void worker_thread() {while (!task_queue.empty()) {auto task = std::move(task_queue.front());task_queue.pop_front();task(); // 執行任務}
}int main() {std::packaged_task<int()> task([]{return 42;});std::future<int> result = task.get_future();task_queue.push_back(std::move(task));std::thread t(worker_thread);t.join();std::cout << "Result: " << result.get() << std::endl;return 0;
}

6. 四者的比較與選擇指南

6.1 功能對比

工具適用場景線程管理靈活性
std::async簡單異步任務自動
std::promise需要手動設置結果的復雜場景手動
std::packaged_task需要傳遞任務對象的場景手動

6.2 選擇建議

  1. 優先考慮std::async:適用于簡單的異步任務
  2. 需要精細控制時使用std::promise
  3. 需要將任務對象傳遞給線程池時使用std::packaged_task

7. 高級主題與最佳實踐

7.1 異常處理

  • 使用promise.set_exception()傳遞異常
  • future.get()時捕獲異常

7.2 超時控制

auto status = future.wait_for(std::chrono::seconds(1));
if (status == std::future_status::ready) {// 任務已完成
} else {// 超時處理
}

7.3 共享結果

使用std::shared_future實現多線程共享異步結果:

std::promise<int> prom;
std::shared_future<int> shared_fut = prom.get_future().share();// 多個線程可以同時訪問shared_fut

8. 總結

C++的異步編程工具提供了不同層次的抽象,從簡單的std::async到更靈活的std::promisestd::packaged_task,開發者可以根據具體需求選擇合適的工具。理解這些工具的特性和適用場景,能夠幫助我們編寫出更高效、更健壯的并發程序。

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

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

相關文章

2021-10-28 C++判斷完全平方數

緣由判斷一個整數是否為完全平方數-編程語言-CSDN問答 整數用平方法小數用5分法逼近。 int 判斷平方數(int n) {//緣由https://ask.csdn.net/questions/7546950?spm1005.2025.3001.5141int a 1;while (a < n / a)if (a*a < n)a;else if (a*a n)return 1;elsereturn 0…

解決weman框架redis報錯:Class “llluminatelRedis\RedisManager“ not found

解決weman框架redis報錯&#xff1a;Class "llluminatelRedis\RedisManager" not found 報錯解決方案 報錯 解決方案 按照手冊執行 composer require psr/container ^1.1.1 illuminate/redis illuminate/events 安裝redis組件 然后restart重啟就行了 php webman s…

Windows 11 電源計劃進階——通過異類策略優化大小核CPU調度

一、為什么需要手動控制大小核調度&#xff1f; 1.1 Intel 12/13/14代酷睿與Win11的適配現狀 Intel 12代酷睿首次引入混合架構設計&#xff08;P-Core性能核 E-Core能效核&#xff09;&#xff0c;Windows 11雖然原生支持線程調度器&#xff08;Thread Director&#xff09;…

文件系統·linux

目錄 磁盤簡介 Ext文件系統 塊 分區 分組 inode 再談inode 路徑解析 路徑緩存 再再看inode 掛載 小知識 磁盤簡介 磁盤&#xff1a;一個機械設備&#xff0c;用于儲存數據。 未被打開的文件都是存在磁盤上的&#xff0c;被打開的加載到內存中。 扇區&#xff1a;是…

如何使用redis做限流(golang實現小樣)

在實際開發中,限流(Rate Limiting)是一種保護服務、避免接口被惡意刷流的常見技術。常用的限流算法有令牌桶、漏桶、固定窗口、滑動窗口等。由于Redis具備高性能和原子性操作,常常被用來實現分布式限流。 下面給出使用Golang結合Redis實現簡單限流的幾種常見方式(以“固定…

手寫ES6 Promise() 相關函數

手寫 Promise() 相關函數&#xff1a; Promise()、then()、catch()、finally() // 定義三種狀態常量 const PENDING pending const FULFILLED fulfilled const REJECTED rejectedclass MyPromise {/*定義狀態和結果兩個私有屬性:1.使用 # 語法&#xff08;ES2022 官方私有字…

Redis學習專題(五)緩存穿透、緩存擊穿、緩存雪崩

目錄 一、緩存穿透 緩存穿透的原因&#xff1a; 緩存穿透的現象&#xff1a; 緩存穿透的解決辦法&#xff1a; 二、緩存擊穿 緩存擊穿的原因&#xff1a; 緩存擊穿的現象&#xff1a; 緩存擊穿的解決辦法: 三、緩存雪崩 緩存雪崩的原因&#xff1a; 緩存雪崩的現象&…

【Hadoop】大數據技術之 MapReduce

目錄 一、MapReduce概述 1.1 MapReduce 定義 1.2 MapReduce優缺點 1.3 MapReduce 核心思想 1.4 MapReduce 進程 1.5 常用數據序列化類型 1.6 MapReduce 編程規范 二、WordCound 案例 2.1 環境準備 2.2 編寫程序 三、MapReduce 工作流程 一、MapReduce概述 1.1 MapRe…

國際前沿知識系列三:解決泛化能力不足問題

目錄 國際前沿知識系列三&#xff1a;解決泛化能力不足問題 一、子類建模法與分類建模法在腦區應變預測中的應用 &#xff08;一&#xff09;子類建模法 案例分析 &#xff08;二&#xff09;分類建模法 案例分析 二、基于遷移學習和數據融合的大腦應變預測模型改良 &a…

client.chat.completions.create方法參數詳解

response client.chat.completions.create(model"gpt-3.5-turbo", # 必需參數messages[], # 必需參數temperature1.0, # 可選參數max_tokensNone, # 可選參數top_p1.0, # 可選參數frequency_penalty0.0, # 可選參數presenc…

iOS 15.4.1 TrollStore(巨魔商店)安裝教程詳解:第二篇

?? iOS 15.4.1 TrollStore(巨魔商店)安裝教程詳解 ? 前言??? 如何安裝 TrollStore?第一步:打開 Safari 瀏覽器第二步:選擇對應系統版本安裝方式第三步:訪問地址,下載配置文件(plist)第四步:安裝配置文件第五步:“jailbreaks.app” 請求安裝 TrollHelper第六步…

SQL的RAND用法和指定生成隨機數的范圍

SQL中的RAND函數能夠滿足多種隨機數生成的需求。通過合理地使用種子、結合一些SQL語句&#xff0c;我們可以實現靈活的隨機數生成。在數據填充、數據處理、數據分析中經常需要用RAND生成的隨機數。 用法1 生成隨機浮點數&#xff0c;其返回值在0&#xff08;包括0&#xff09;…

AppAgentx 開源AI手機操控使用分享

項目地址: https://appagentx.github.io/?utm_sourceai-bot.cn GitHub倉庫: https://github.com/Westlake-AGI-Lab/AppAgentX/tree/main arXiv技術論文:https://arxiv.org/pdf/2503.02268 AppAgentx是什么: AppAgentX 是西湖大學推出的一種自我進化式 GUI 代理框架。它通過…

[原創]X86C++反匯編01.IDA和提取簽名

https://bpsend.net/thread-415-1-1.html 用VC6.0新建一個控制臺工程 編譯成 debug 和 Release 2個版本 應ida分別查看2種版本的程序 高版本ida 可能會直接定位到函數入口,正常情況下,我們需要先調試找到關鍵,找到關鍵以后點再通過調試設置api斷點,讀寫斷點等,找到程序的關鍵…

vs2022 Qt Visual Studio Tools插件設置

安裝之后&#xff0c;需要指定QT中msvc編譯器的位置&#xff0c;點擊下圖Location右邊的按鈕即可 選擇msvc2022_64\bin目錄下的 qmake.exe 另一個問題,雙擊UI文件不能打開設計界面 設置打開方式 選擇msvc2022_64\bin目錄下的designer.exe 確定即可 然后設置為默認值即可 確定…

C++代碼隨想錄刷題知識分享-----兩數之和(哈希表)三種算法逐個擊破

題目描述 給定一個整數數組 nums 和一個目標值 target&#xff0c;請你在該數組中找出和為目標值的那兩個整數&#xff0c;并返回它們的下標。 每個輸入只對應一個答案。同一個元素不能重復使用。你可以按任意順序返回答案。 示例 輸入&#xff1a; nums [2, 7, 11, 15], ta…

List介紹

什么是List 在集合框架中&#xff0c;List是一個接口&#xff0c;繼承自Collection Collection也是一個接口&#xff0c;該接口中規范了后序容器中常用的一些方法 Iterable也是一個接口&#xff0c;表示實現該接口的類是可以逐個元素進行遍歷的&#xff0c;具體如下&#xff1…

深入理解API:從概念到實戰

引言 在現代軟件開發中&#xff0c;API&#xff08;Application Programming Interface&#xff09;無處不在。無論是調用第三方服務、訪問操作系統功能&#xff0c;還是使用編程語言的標準庫&#xff0c;API 都扮演著關鍵角色。但對于許多初學者來說&#xff0c;API 仍然是一…

織夢dedecms登錄后臺出現Safe Alert Request Error step 2

今天一個客戶在安裝織夢dedecms時候&#xff0c;安裝完成后登錄后臺就出現“Safe Alert Request Error step 2”&#xff0c;常用dedecms的朋友都知道&#xff0c;這是織夢的安全機制&#xff0c;在程序覺得有sql注入等攻擊時候&#xff0c;會有這種提示。 1、起初我以為是文件…

BLIP3-o:理解和生成統一的多模態模型

文章目錄 研究背景BLIP3-o 框架3個關鍵問題BLIP3-o模型總結 paper link: https://arxiv.org/pdf/2505.09568from saleforce research 研究背景 隨著gpt4o圖像生成和編輯的應用火爆&#xff0c;如何構造能夠同時處理圖像理解和生成任務的統一多模態模型&#xff0c;成為研究的…