c++oding="utf-8" ?>
std::async默认不真正异步,可能同步执行;根本原因是默认策略为std::launch::deferred,仅延迟至get()/wait()时在当前线程执行,须显式指定std::launch::async才强制新线程立即异步运行。

std::async 默认不真正异步,可能同步执行
调用 std::async 后函数立刻执行、阻塞等待返回,是常见误解。根本原因是默认启动策略为 std::launch::deferred —— 仅注册延迟调用,直到你调用 get() 或 wait() 才真正执行,且在当前线程运行。
- 必须显式传入
std::launch::async才强制派生新线程执行 - 只写
std::async([]{...})等价于std::async(std::launch::deferred, ...) - 混合使用时(如未指定策略),调度行为由实现决定,不可移植
正确启动真正异步任务的写法
要确保后台线程立即运行,必须用 std::launch::async 显式指定,并注意 std::future 生命周期管理:
auto fut = std::async(std::launch::async, [] {
std::this_thread::sleep_for(2s);
return 42;
});
// 此时 lambda 已在另一线程中运行
int result = fut.get(); // 阻塞直到完成,获取返回值
- 漏掉
std::launch::async→ 可能 deferred,无并发效果 - 忘记保存
std::future→ 对象析构时若未get()或wait(),会阻塞并等待完成(隐式同步) - 多个
std::async调用不保证并行度,线程池由标准库实现控制,无法配置
std::async 和 std::thread 的关键区别在哪
两者都启新线程,但语义和资源管理完全不同:
-
std::async返回std::future,天然支持带返回值、异常传播、自动生命周期等待 -
std::thread不返回值,需手动同步(join()/detach()),异常不跨线程传递 -
std::async的线程可能被复用或延迟创建;std::thread每次都新建 OS 线程,开销更可控但更重 - 异常从 async 任务抛出后,会在
get()时重新抛出;thread 中未捕获异常直接终止程序
实际使用中最容易踩的坑
不是语法错,而是对隐式行为缺乏警惕:
-
std::async返回的std::future是临时对象?比如std::async(...).get()→ 临时 future 析构时阻塞,等同于同步调用 - lambda 捕获局部变量用
[&],但原变量在主线程提前销毁 → 悬垂引用,未定义行为 - 误以为
std::async自带线程池,大量调用导致线程数爆炸(实际取决于 lib 实现,libc++/MSVC 行为不同) - 没处理
std::future_error:例如重复调用get()抛出std::future_errc::no_state
真正需要可靠异步+结果管理时,std::async 很方便;但对并发控制、取消、超时有要求,它就力不从心了——得换更底层的机制或第三方库。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











