【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.mzph.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…