商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > C++如何使用std::async返回一个带延迟的结果

C++如何使用std::async返回一个带延迟的结果

  发布于2026-07-11 阅读(0)

扫一扫,手机访问

很多开发者在使用 std::async 时,会下意识以为它默认就是延迟执行——其实不然。必须显式指定 std::launch::deferred,才能真正做到“调用 get()wait() 时才执行函数”。而且每次调用都会重新执行,既不会缓存结果,也不保证线程安全。这个细节一旦忽视,很容易在项目里埋下隐形的坑。

C++如何使用std::async返回一个带延迟的结果

std::async 默认不延迟执行,必须显式指定 launch policy

直接调用 std::async 却不传 launch policy 时,行为由实现决定: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() 都重新执行函数。

  • 如果 lambda 有副作用(比如修改全局变量、发网络请求),多次 get() 会重复触发
  • 它不是 std::call_oncestd::once_flag 的替代品
  • 若需真正“首次 get 才执行、之后复用结果”,得自己包装一层(比如用 std::optional + mutex),std::future 本身不提供该语义
  • 跨线程访问同一个 deferred future 是安全的,但执行时机取决于哪个线程先调 get()——无序,不可预测

真正难的不是让代码晚点跑,而是搞清“谁在什么时候、以什么方式触发它”。std::launch::deferred 看似简单,但它把执行时机完全交给了 future 的消费者。一旦逻辑分散在多处调用 get(),很容易漏掉某次调用导致函数从未执行,或者重复执行。这种隐式控制流,比显式 sleep + thread 更容易出错。

本文转载于:https://www.php.cn/faq/2801937.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注