std::async默认策略行为不可靠,应显式指定std::launch::async;future.get()仅能调用一次且阻塞等待,重复调用抛异常;future析构前未get/wait会隐式等待任务完成;shared_future支持多线程多次取值。

std::async 启动异步任务时,launch策略决定执行时机
不显式指定 std::launch 策略,std::async 可能延迟执行(lazy evaluation),直到调用 get() 或 wait() 才真正启动线程——这常被误认为“卡住”或“没运行”。
-
std::async(std::launch::async, ...):强制立即在新线程中执行 -
std::async(std::launch::deferred, ...):仅在get()/wait()时同步执行(无并发) - 默认策略是两者或运算:
std::launch::async | std::launch::deferred,具体行为由实现决定,不可依赖
实际开发中,除非明确需要延迟求值,否则应显式写 std::launch::async,避免行为不一致。
future.get() 会阻塞,且只能调用一次
std::future::get() 是获取结果的唯一方式,但它有两大硬约束:
- 首次调用会阻塞,直到异步任务完成;若任务已结束,则立即返回结果
- 第二次调用会抛出
std::future_error(错误码为std::future_errc::no_state) - 调用
get()后,future对象进入无效状态,不能再用于wait()或再次get()
常见错误:在循环里反复对同一个 future 调用 get(),或未检查是否已取值就二次取值。建议用 std::move 转移所有权,或用 std::shared_future 支持多次读取。
立即学习“C++免费学习笔记(深入)”;
async 返回的 future 不持有线程资源,需确保生命周期
std::async 返回的 std::future 本身不管理线程,它只负责同步和取值。但 C++ 标准要求:如果 future 在析构前未调用 get() 或 wait(),其关联的异步任务**必须等待完成才允许析构**(即隐式 join)。这意味着:
- 若任务长时间运行,而
future被提前销毁(比如函数提前 return),主线程会卡住等它结束 - 无法像
std::thread那样主动 detach ——async不提供脱离机制 - 想避免阻塞析构?必须显式调用
wait_for(0s)判断是否就绪,或改用std::packaged_task+std::thread手动管理
这也是为什么高并发场景下,std::async 并不适合作为轻量级任务提交接口——它的资源绑定太重,容易引发意外等待。
shared_future 支持多处等待/取值,但开销略高
当多个线程都需要访问同一异步结果时,原始 std::future 无法拷贝。这时要用 std::shared_future:
- 通过
future.share()或构造函数从future转换而来 - 可拷贝、可多线程并发调用
get()(只要原future已完成) - 内部带引用计数,比
future多一点原子操作开销,但通常可忽略
示例:auto sf = std::async(std::launch::async, []{ return 42; }).share();,之后可把 sf 分发给多个观察者。
注意:shared_future 的 get() 仍只对已完成状态安全;若在任务结束前并发调用多个 get(),它们都会阻塞到完成,但不会重复执行任务。











