【Effective Modern C++】第七章 并发API:35. 优先考虑基于任务的编程而非基于线程的编程

两种异步执行方式的直观对比

基于线程(thread-based):直接创建 std::thread
c++ 复制代码
int doAsyncWork();
std::thread t(doAsyncWork); // 直接创建线程执行函数
  • 无直接获取返回值的方式;
  • 若函数抛出异常,程序会直接调用std::terminate终止。
基于任务(task-based):使用 std::async
c++ 复制代码
auto fut = std::async(doAsyncWork); // 提交任务,返回future对象
  • 代码更简洁;
  • futureget()函数可获取返回值,还能捕获函数抛出的异常(避免程序终止);
  • 线程管理的责任交给标准库,而非开发者。

理解线程的三层含义

线程类型 定义
硬件线程 CPU 核心提供的真实执行单元,是计算的物理载体。
软件线程(OS 线程) 操作系统管理的线程,运行在硬件线程上,数量可多于硬件线程(阻塞时 OS 调度其他线程)。
std::thread C++ 中 "软件线程" 的句柄,可能为空(默认构造、移动、join、detach 后无对应软件线程)。

基于线程编程的痛点

直接使用std::thread的核心问题在于需要开发者手动处理线程管理的复杂问题:

  • 线程资源有限 :系统支持的软件线程数量有上限,创建超出限额的std::thread会抛出std::system_error异常;即使函数本身noexcept,也可能触发此异常,且异常处理逻辑复杂(比如回退到当前线程执行会导致负载不均、GUI 线程响应慢)。

  • 资源超额(oversubscription) :可运行的软件线程数 > 硬件线程数时,OS 会对线程做时间切片,引发上下文切换

    • 上下文切换本身增加系统开销;
    • 若线程切换到不同硬件核心,会导致 CPU 缓存失效(无可用数据 / 指令),还会 "污染" 原核心的缓存,进一步降低性能。
  • 优化难度极高:软件线程与硬件线程的最佳比例是动态变化的(比如程序从 IO 密集型变为计算密集型),且依赖硬件特性(缓存大小、核心数),跨平台适配几乎不可能。

基于任务编程的优势

std::async的价值是将线程管理的责任交给标准库,规避上述痛点:

  • 灵活的调度策略 :默认启动策略下,std::async不保证创建新线程;当系统线程耗尽 / 资源超额时,会将任务调度到 "等待结果的线程"(调用fut.get()/fut.wait()的线程)上执行,避免线程创建失败或资源超额。
  • 更智能的运行时调度 :标准库调度器(部分实现采用线程池 + 工作窃取算法)比开发者更了解系统全局状态(所有执行过程),能更好地实现负载均衡,优化上下文切换和缓存利用。
  • 天然支持结果 / 异常处理futureget()函数可获取异步执行的返回值,或捕获函数抛出的异常,避免程序终止。

仍需使用 std::thread 的特殊场景

  • 需要访问底层线程 API:std::thread提供native_handle()成员函数,可操作线程优先级、亲和性等(std::future无此能力);
  • 可精准优化线程使用:比如部署在固定硬件上、执行概况明确的服务器(作为唯一关键进程);
  • 实现标准库不支持的线程技术:比如特定平台未被 C++ 标准库实现的线程池。

总结

  1. 基于线程的编程(std::thread)需要手动处理线程耗尽、资源超额、负载均衡等复杂问题,且无法直接获取异步执行结果,函数异常会导致程序终止;
  2. 基于任务的编程(std::async)将线程管理交给标准库,默认启动策略可规避大部分线程管理痛点,还能通过 future 获取结果 / 捕获异常;
  3. 仅在需要访问底层线程 API、精准优化线程使用或实现非标线程技术时,才考虑直接使用 std::thread。

原著在线阅读地址

相关推荐
小肝一下18 小时前
每日两道力扣,day5
数据结构·c++·算法·leetcode·职场和发展·hot100
OOJO1 天前
c++---list介绍
c语言·开发语言·数据结构·c++·算法·list
会编程的土豆1 天前
【数据结构与算法】动态规划
数据结构·c++·算法·leetcode·代理模式
6Hzlia1 天前
【Hot 100 刷题计划】 LeetCode 78. 子集 | C++ 回溯算法题解
c++·算法·leetcode
所以遗憾是什么呢?1 天前
【题解】Codeforces Round 1081 (Div. 2)
数据结构·c++·算法·acm·icpc·ccpc·xcpc
白藏y1 天前
【C++】muduo接口补充
开发语言·c++·muduo
xiaoye-duck1 天前
《算法题讲解指南:递归,搜索与回溯算法--综合练习》--14.找出所有子集的异或总和再求和,15.全排列Ⅱ,16.电话号码的字母组合,17.括号生成
c++·算法·深度优先·回溯
OOJO1 天前
c++---vector介绍
c语言·开发语言·数据结构·c++·算法·vim·visual studio
Tanecious.1 天前
蓝桥杯备赛:Day5-P1706 全排列问题
c++·蓝桥杯
胖咕噜的稞达鸭1 天前
C++技术岗面试经验总结
开发语言·网络·c++·网络协议·tcp/ip·面试