std::async 默认不延迟执行,必须显式指定 std::launch::deferred 才能实现延迟;此时函数仅在 get()/wait() 调用时执行,且每次调用均重新执行,不缓存结果、不保证线程安全。

std::async 默认不延迟执行,必须显式指定 launch policy
直接调用 std::async 时,如果不传 launch policy,行为是 implementation-defined:有些编译器(如 MSVC)默认用 std::launch::deferred,有些(如 GCC libstdc++)默认用 std::launch::async。这意味着你不能依赖“自动延迟”,必须明确写出来。
- 要延迟执行(即调用
get()或wait()时才真正运行),必须传std::launch::deferred - 只传一个可调用对象(比如 lambda)而没指定 policy,等价于
std::async(std::launch::async | std::launch::deferred, ...),调度完全由实现决定 - 若想确保延迟,写法必须是:
std::async(std::launch::deferred, []{ return 42; })
延迟结果的获取时机决定实际执行时间
std::async 返回的是 std::future,但 std::launch::deferred 模式下,它不启动线程,也不预分配资源——函数体直到你调用 get()、wait() 或 wait_for() 才执行。这点和 std::launch::async 截然不同。
-
future.get()会阻塞并立即执行被延迟的函数,返回值 -
future.wait()阻塞但不取值,仍需后续get() -
future.wait_for(...)在 deferred 模式下永远返回std::future_status::deferred,因为它根本没在跑,谈不上“等待超时” - 注意:
std::future析构时若未调用get()或wait(),且是 deferred 模式,不会执行函数,也不会报错——函数就这么丢了
延迟 + 定时触发?得自己加 sleep,async 不提供 delay 参数
std::async 本身没有“延迟 N 秒后执行”的接口。所谓“带延迟的结果”,其实是组合使用:std::launch::deferred + 函数体内手动 sleep,或者用 std::launch::async + 线程内 sleep。两者语义不同。
- 延迟执行(deferred)+ 内部 sleep:调用
get()时才开始计时,适合“用户触发后等几秒再算”场景 - 异步执行(async)+ 内部 sleep:提交即启动线程,sleep 在后台发生,适合“定时任务”类需求
- 示例(deferred 延迟 2 秒):
auto f = std::async(std::launch::deferred, []{ std::this_thread::sleep_for(2s); return "done"; });;之后f.get()才真正 sleep 并返回 - 别用
std::chrono::delay_until—— 标准库没有这个函数,容易拼错成std::this_thread::sleep_until
常见误用:把 deferred future 当作 timer 或 lazy init 的安全封装
很多人想用 std::async(std::launch::deferred, ...) 实现懒加载或防重入,但要注意:它不保证线程安全,也不缓存结果。每次 get() 都重新执行函数。
立即学习“C++免费学习笔记(深入)”;
- 如果 lambda 有副作用(比如修改全局变量、发网络请求),多次
get()会重复触发 - 它不是
std::call_once或std::once_flag的替代品 - 若需真正“首次 get 才执行、之后复用结果”,得自己包装一层(比如用
std::optional+ mutex),std::future本身不提供该语义 - 跨线程访问同一个 deferred future 是安全的,但执行时机取决于哪个线程先调
get()——无序,不可预测
std::launch::deferred 看似简单,但它把执行时机完全交给了 future 的消费者,一旦逻辑分散在多处调用 get(),就很容易漏掉某次调用导致函数从未执行,或者重复执行。这种隐式控制流,比显式 sleep + thread 更容易出错。


















