C++如何使用std::async进行异步编程?(future用法)

9次阅读

必须通过 std::future 的 get()或 wait()获取结果或等待完成,否则可能阻塞析构;支持 async、deferred 及二者组合策略,future 为单次使用,异常被捕获并重抛,shared_future 允许多次读取。

C++ 如何使用 std::async 进行异步编程?(future 用法)

std::async 启动 异步任务 后,必须通过 std::future 获取结果或等待完成;不调用 get()wait() 可能导致线程资源未释放、程序阻塞在析构时。

std::async 的三种启动策略

std::async 支持三种 std::launch 策略,决定任务何时执行:

  • std::launch::async:强制新线程立即执行(真正异步)
  • std::launch::deferred:延迟执行,直到调用 future.get()future.wait() 时才在当前线程运行(类似惰性求值)
  • std::launch::async | std::launch::deferred(默认):由 标准库 决定——通常优先异步,但可能退化为延迟执行(尤其系统负载高时)

显式指定策略更可控。例如:auto f = std::async(std::launch::async, []{return 42;});

future 的核心操作:get() 与 wait()

std::future 是单次使用的同步原语,关键行为如下:

立即学习C++ 免费学习笔记(深入)”;

  • get():阻塞等待结果,返回值(或抛出异常),且只能调用一次;第二次调用会抛出 std::future_error
  • wait():仅阻塞等待完成,不取值,可多次调用(但无实际意义)
  • wait_for()wait_until():带超时的等待,返回 std::future_statusready / timeout / deferred

注意:即使任务已结束,get() 仍会移动内部存储的值或异常,之后 future 处于无效状态。

处理异常和共享状态

异步函数内抛出的异常不会崩溃程序,而是被捕获并存入 future 中:

  • 调用 get() 时,若任务抛过异常,该异常会被重新抛出(类型不变)
  • 多个 future 可通过 std::shared_future 共享同一结果(适用于多处读取场景)
  • std::shared_future 支持多次 get(),需由 future.share() 转换获得

示例:auto sf = f.share(); auto a = sf.get(); auto b = sf.get(); // 合法

生命周期管理要点

std::future 析构时,若关联的异步任务仍在运行且策略为 async,析构会阻塞直到任务完成——这是常见陷阱:

  • 避免临时 future:如 std::async(……).get(); 会立刻阻塞,失去异步意义
  • 确保 future 对象存活到你准备取结果时;推荐用命名变量持有
  • 若需“只管启动、不关心结果”,可用 std::async(std::launch::async, ……);(但注意析构仍会等)

真正“fire-and-forget”应配合 std::thread + 分离,或封装成不返回 future 的接口。

text=ZqhQzanResources