【C/C++】C++并發編程:std::async與std::thread深度對比

文章目錄

  • C++并發編程:std::async與std::thread深度對比
    • 1 核心設計目的以及區別
    • 2 詳細對比分析
    • 3 代碼對比示例
    • 4 適用場景建議
    • 5 總結

C++并發編程:std::async與std::thread深度對比

在 C++ 中,std::asyncstd::thread 都是用于并發編程的工具,但它們在實現方式、資源管理和適用場景上有顯著區別。


1 核心設計目的以及區別

特性std::asyncstd::thread
目標簡化異步任務的啟動和結果獲取提供底層線程的直接控制
抽象層級高級抽象(封裝線程和結果管理)低級抽象(直接操作線程)
典型場景需要異步執行并獲取結果的短期任務需要精細控制線程生命周期的復雜任務
特性std::threadstd::async
線程創建直接創建新線程可能創建新線程,也可能延遲執行(取決于策略)
返回值無返回值,需通過共享變量傳遞結果返回 std::future,可異步獲取結果
資源管理需手動管理線程生命周期(join()/detach()自動管理任務生命周期,future 析構時自動處理
異常處理線程內未捕獲的異常會導致程序崩潰異常會被捕獲并存儲在 future
執行策略總是立即執行可指定 std::launch::async(立即執行)或 std::launch::deferred(延遲執行)
適用場景需要精細控制線程行為(如優先級、同步)需要異步執行并獲取結果,或延遲執行任務
特性std::asyncstd::thread
返回值傳遞通過 std::future 自動獲取結果需手動傳遞(如 std::promise 或全局變量)
異常處理異常通過 future.get() 自動傳遞到調用線程線程內未捕獲的異常會導致 std::terminate
示例auto f = std::async(func); try { f.get(); } catch(...) {} std::promise<int> p; auto f = p.get_future(); std::thread t([&p]{ try { p.set_value(func()); } catch(...) { p.set_exception(...); } });
特性std::asyncstd::thread
線程生命周期std::future 析構時自動等待線程完成(若策略為 async必須顯式調用 join()detach(),否則程序終止
資源泄漏風險低(自動管理)高(需手動管理)
示例cpp { auto f = std::async(func); } // 自動等待 cpp std::thread t(func); t.join(); // 必須顯式調用
特性std::asyncstd::thread
線程池支持可能使用線程池(依賴編譯器實現)每次創建新線程
適用場景短期任務(避免頻繁創建線程的開銷)長期任務或需要獨占線程的場景
性能風險若默認策略非異步,可能意外延遲執行頻繁創建線程可能導致資源耗盡

2 詳細對比分析

  1. 線程創建與執行
  • std::thread

    • 強制創建新線程:無論系統資源是否充足,都會立即啟動新線程執行任務。

    • 資源風險:若線程數量過多(如超過系統限制),可能導致程序崩潰。

    • 示例:

      std::thread t([](){ /* 任務代碼 */ });
      t.join(); // 必須手動等待線程結束
      
  • std::async

    • 策略控制:
      ? std::launch::async:強制創建新線程執行任務。
      ? std::launch::deferred:延遲執行,僅在調用 get()wait() 時執行(不創建新線程)。
      ? 默認策略(async | deferred):由系統決定是否創建線程。

    • 資源優化:可能復用線程池中的線程,減少創建開銷。

    • 示例:

      auto fut = std::async(std::launch::async, [](){ return 42; });
      int result = fut.get(); // 阻塞等待結果
      
  1. 返回值與結果獲取
  • std::thread

    • 無法直接獲取返回值,需通過共享變量或回調函數傳遞結果。
    • 示例:
      int result = 0;
      std::thread t([&result](){ result = 42; });
      t.join();
      
  • std::async

    • 通過 std::future 自動獲取返回值,支持異步等待。

    • 示例:

      auto fut = std::async([](){ return 42; });
      int result = fut.get(); // 阻塞獲取結果
      
  1. 異常處理
  • std::thread

    • 線程內拋出的異常若未被捕獲,會導致程序終止。

    • 示例:

      std::thread t([](){ throw std::runtime_error("error"); });
      t.join(); // 程序崩潰
      
  • std::async

    • 異常會被捕獲并存儲在 std::future 中,調用 get() 時重新拋出。

    • 示例:

      auto fut = std::async([](){ throw std::runtime_error("error"); });
      try { fut.get(); } 
      catch (const std::exception& e) { /* 處理異常 */ }
      
  1. 性能與資源消耗
  • std::thread

    • 高開銷:線程創建和銷毀涉及操作系統調度,頻繁使用可能導致性能瓶頸。
    • 適用場景:需要長期運行的獨立任務(如后臺服務線程)。
  • std::async

    • 低開銷:可能復用線程池中的線程,減少創建/銷毀成本。
    • 適用場景:短時任務或需要靈活調度的工作(如并行計算、I/O 密集型操作)。

3 代碼對比示例

任務:并行計算并返回結果

  • 使用 std::thread

    #include <iostream>
    #include <thread>
    #include <future>int compute() {return 42;
    }int main() {std::thread t(compute);// 無法直接獲取結果,需通過共享變量t.join();return 0;
    }
    
  • 使用 std::async

    #include <iostream>
    #include <future>int compute() {return 42;
    }int main() {auto fut = std::async(compute);int result = fut.get(); // 直接獲取結果std::cout << "Result: " << result << std::endl;return 0;
    }
    

4 適用場景建議

場景推薦工具原因
需要獲取異步任務結果std::async通過 std::future 簡化結果傳遞,避免共享變量競爭
需要控制線程優先級或調度策略std::thread提供底層線程控制能力
短時任務或高并發場景std::async可能復用線程池,減少資源開銷
長時間運行的后臺服務線程std::thread需要保持線程活躍狀態
  • 優先 std::async 的場景:

    • 需要異步執行并獲取結果。
    • 關注異常安全和代碼簡潔性。
    • 短期任務,避免手動管理線程。
  • 優先 std::thread 的場景:

    • 需要精確控制線程生命周期(如分離線程、自定義調度)。
    • 長期運行的后臺任務(如服務線程)。
    • 需要跨線程共享復雜狀態或資源。

5 總結

  • std::thread:適合需要直接控制線程行為、長期運行的任務,但需手動管理生命周期和結果傳遞。
  • std::async:適合需要異步執行并獲取結果、或希望系統自動優化資源使用的場景,但對執行策略需謹慎選擇。
  • std::async 的隱藏阻塞:std::future 析構時會隱式等待任務完成,可能導致意外阻塞。
  • 線程局部存儲(TLS):std::async 的線程可能復用,導致 TLS 狀態殘留。
  • 編譯器差異:std::async 的線程池行為(如線程復用策略)可能因編譯器實現不同而不同。
維度std::asyncstd::thread
結果獲取自動通過 future需手動使用 promise 或共享變量
異常傳播自動傳遞異常需手動捕獲并處理
線程管理自動等待線程完成需顯式調用 join()/detach()
靈活性適合簡單任務適合需要精細控制的場景
性能優化可能復用線程(依賴實現)直接控制線程創建和銷毀

關鍵原則:

  • 若需結果或異常安全,優先選擇 std::async
  • 若需精細控制線程行為(如優先級、同步),使用 std::thread

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

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

相關文章

Axure疑難雜癥:垂直菜單展開與收回(4大核心問題與專家級解決方案)

親愛的小伙伴,在您瀏覽之前,煩請關注一下,在此深表感謝!如有幫助請訂閱專欄! Axure產品經理精品視頻課已登錄CSDN可點擊學習https://edu.csdn.net/course/detail/40420 課程主題:垂直菜單展開與收回 主要內容:超長菜單實現、展開與收回bug解釋、Axure9版本限制等問題解…

ASIC和FPGA,到底應該選擇哪個?

ASIC和FPGA各有優缺點。 ASIC針對特定需求&#xff0c;具有高性能、低功耗和低成本&#xff08;在大規模量產時&#xff09;&#xff1b;但設計周期長、成本高、風險大。FPGA則適合快速原型驗證和中小批量應用&#xff0c;開發周期短&#xff0c;靈活性高&#xff0c;適合初創企…

DAY 30 模塊和庫的導入

知識點回顧&#xff1a; 1.導入官方庫的三種手段 2.導入自定義庫/模塊的方式 3.導入庫/模塊的核心邏輯&#xff1a;找到根目錄&#xff08;python解釋器的目錄和終端的目錄不一致&#xff09; 作業&#xff1a;自己新建幾個不同路徑文件嘗試下如何導入 import math # 導入…

MyBatis:動態SQL

文章目錄 動態SQLif標簽trim標簽where標簽set標簽foreach標簽include標簽和sql標簽 Mybatis動態SQL的官方文檔&#xff1a; https://mybatis.net.cn/dynamic-sql.html 動態SQL 動態SQL是 MyBatis的強大特性之一,如果是使用JDBC根據不同條件拼接sql很麻煩&#xff0c;例如拼接…

Java - Junit框架

單元測試&#xff1a;針對最小的功能單元(方法)&#xff0c;編寫測試代碼對該功能進行正確性測試。 Junit&#xff1a;Java語言實現的單元測試框架&#xff0c;很多開發工具已經集成了Junit框架&#xff0c;如IDEA。 優點 編寫的測試代碼很靈活&#xff0c;可以指某個測試方法…

學生成績管理系統Java實戰(Spring Boot+MyBatis Plus)

文章目錄 一、系統需求分析&#xff08;避坑指南&#xff09;二、技術選型&#xff08;2024新版&#xff09;三、數據庫設計&#xff08;三大核心表&#xff09;1. 學生表&#xff08;student&#xff09;2. 課程表&#xff08;course&#xff09;3. 成績表&#xff08;score&a…

MySQL安裝實戰指南:Mac、Windows與Docker全平臺詳解

MySQL作為世界上最流行的開源關系型數據庫&#xff0c;是每位開發者必須掌握的基礎技能。本指南將手把手帶你完成三大平臺的MySQL安裝&#xff0c;從下載到配置&#xff0c;每個步驟都配有詳細說明和截圖&#xff0c;特別適合新手學習。 一、Mac系統安裝MySQL 1.1 通過Homebre…

多模態大語言模型arxiv論文略讀(七十九)

AIM: Let Any Multi-modal Large Language Models Embrace Efficient In-Context Learning ?? 論文標題&#xff1a;AIM: Let Any Multi-modal Large Language Models Embrace Efficient In-Context Learning ?? 論文作者&#xff1a;Jun Gao, Qian Qiao, Ziqiang Cao, Zi…

[Harmony]封裝一個可視化的數據持久化工具

1.添加權限 在module.json5文件中添加權限 // 聲明應用需要請求的權限列表 "requestPermissions": [{"name": "ohos.permission.DISTRIBUTED_DATASYNC", // 權限名稱&#xff1a;分布式數據同步權限"reason": "$string:distrib…

利用html制作簡歷網頁和求職信息網頁

前言 大家好&#xff0c;我是maybe。今天下午初步學習了html的基礎知識。做了兩個小網頁&#xff0c;一個網頁是簡歷網頁&#xff0c;一個網頁是求職信息填寫網頁。跟大家分享一波~ 說明:我不打算上傳圖片。所以如果有朋友按照我的代碼運行網頁&#xff0c;會出現一個沒有圖片…

Vue 3 實現后端 Excel 文件流導出功能(Blob 下載詳解)

&#x1f4a1; 本文以告警信息導出為例&#xff0c;介紹 Vue 3 中如何通過 Axios 調用后端接口并處理文件流&#xff0c;實現 Excel 自動下載功能。 &#x1f4d1; 目錄 一、前言 二、后端接口說明 三、前端實現思路 四、導出功能完整代碼 五、常見問題處理 六、效果展示 …

HarmonyOS AVPlayer 音頻播放器

鴻蒙文檔中心&#xff1a;使用AVPlayer播放視頻(ArkTS)文檔中心https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/video-playback 這張圖描述的是 HarmonyOS AVPlayer 音頻播放器的狀態流轉過程&#xff0c;展示了 AVPlayer 在不同狀態之間的切換條件和關鍵操作…

Java面試場景:從音視頻到AI應用的技術探討

面試場景&#xff1a;音視頻與AI應用技術的碰撞 在某互聯網大廠的面試中&#xff0c;面試官王先生與求職者明哥展開了一場關于音視頻技術與AI應用的對話。 第一輪提問&#xff1a;音視頻場景 面試官&#xff1a;明哥&#xff0c;你能談談在音視頻場景中&#xff0c;Spring B…

【深度學習】殘差網絡(ResNet)

如果按照李沐老師書上來&#xff0c;學完 VGG 后還有 NiN 和 GoogLeNet 要學&#xff0c;但是這兩個我之前聽都沒聽過&#xff0c;而且我看到我導師有發過 ResNet 相關的論文&#xff0c;就想跳過它們直接看后面的內容。 現在看來這不算是不踏實&#xff0c;因為李沐老師說如果…

Vue3學習(組合式API——父、子組件間通信詳解)

目錄 一、組合式API下的父組件傳子組件。(自定義屬性) &#xff08;1&#xff09;基本思想。 &#xff08;2&#xff09;核心注意點。(defineProps) &#xff08;3&#xff09;傳遞簡單類型數據。 &#xff08;4&#xff09;傳遞對象類型數據。(v-bind"對象類型數據"…

W5500使用ioLibrary庫創建TCP客戶端

1、WIZnet全硬件TCP/IP協議棧 WIZnet全硬件TCP/IP協議棧,支持TCP,UDP,IPv4,ICMP,ARP,IGMP以及PPPoE協議。 以太網&#xff1a;支持BSD和WIZCHIP&#xff08;W5500/W5300/W5200/W5100/W5100S&#xff09;的SOCKET APIs驅動程序。 互聯網&#xff1a; DHCP客戶端 DNS客戶端 FTP客…

管理Oracle Data Guard的最佳實踐

Oracle Data Guard的中文名字叫數據衛士&#xff0c;顧名思義&#xff0c;它是生產庫的一道保障。所以管理Data Guard是DBA的一項重要工作之一&#xff0c;管理Data Guard時主要有以下幾個注意點需要引起重視。 備份庫的歸檔日志積壓 一般情況下&#xff0c;生產庫的歸檔日志是…

BootCDN介紹(Bootstrap主導的前端開源項目免費CDN加速服務)

文章目錄 BootCDN前端開源項目CDN加速服務全解析什么是BootCDN技術原理與架構CDN技術基礎BootCDN架構特點1. 全球分布式節點網絡2. 智能DNS解析系統3. 高效緩存管理機制4. 自動同步更新機制5. HTTPS和HTTP/2協議支持 BootCDN的核心優勢速度與穩定性開源免費資源豐富度技術規范遵…

2025 Java 微信小程序根據code獲取openid,二次code獲取手機號【工具類】拿來就用

一、controller調用 /*** 登錄** author jiaketao* since 2024-04-10*/ RestController RequestMapping("/login") public class LoginController {/*** 【小程序】登錄獲取session_key和openid** param code 前端傳code* return*/GetMapping("/getWXSessionKe…

軟件架構風格系列(3):管道 - 過濾器架構

文章目錄 前言一、從生活場景到架構原理&#xff0c;看懂管道 - 過濾器的核心邏輯&#xff08;一&#xff09;什么是管道 - 過濾器架構&#xff1f;&#xff08;二&#xff09;核心組件拆解 二、架構設計圖&#xff1a;一圖看懂管道 - 過濾器架構全貌三、Java 示例代碼&#xf…