【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。

原著在线阅读地址

相关推荐
handler011 小时前
Linux 进程探索:从 PCB 管理到 fork() 的写时拷贝
linux·c语言·c++·笔记·学习
众少成多积小致巨1 小时前
GNU Make 核心指南
android·c++
谭欣辰2 小时前
详细讲解 C++ 状压 DP
开发语言·c++·动态规划
William_wL_2 小时前
【C++】stack和queue的使用和实现(附加deque的简单介绍)
开发语言·c++
山甫aa2 小时前
二叉树遍历----从零开始的数据结构
数据结构·c++·二叉树
cpp_25013 小时前
P2249 【深基13.例1】查找
数据结构·c++·算法·题解·二分·洛谷
苏宸啊3 小时前
C++智能指针
c++
OYangxf4 小时前
基于epoll的单线程Reactor:Tinyredis的网络层实现
c++·redis
yinbinggang4 小时前
vmware安装虚拟机
c++
小小de风呀5 小时前
de风——【从零开始学C++】(三):类和对象(中序):默认成员函数全解析
开发语言·c++