std::async默认策略不保证真异步,需显式指定std::launch::async;std::future::get()仅能调用一次且阻塞,未调用则析构时隐式wait;不支持多消费者,须用std::shared_future或std::move转移所有权;异常在get()时重抛。
默认情况下 std::async 不一定真正并发执行——它可能延迟到 get() 或 wait() 时才同步运行(std::launch::deferred 策略)。这常导致“以为异步,实则卡主线程”的问题。
std::launch::async 强制新开线程:auto fut = std::async(std::launch::async, []{ return 42; });deferred,GCC/Clang 多数情况走 async,但不可依赖std::launch::async 任务共享线程池(标准未规定池大小,实际由实现决定)get() 是获取结果的唯一合法方式,但它有强副作用:首次调用后,该 std::future 对象进入无效状态,再次调用会抛出 std::future_error(错误码为 std::future_errc::no_state)。
valid() 检查是否还持有有效状态:if (fut.valid()) { auto res = fut.get(); }wait() 更安全get() 或 wait(),会导致析构时隐式调用 wait() —— 这可能让你在意外位置被阻塞std::future 是独占所有权类型,移动后原对象失效,且不能拷贝。这意味着它无法像 std::shared_future 那样被多个线程同时等待或取值。
std::shared_future:auto fut = std::async([]{ return "done"; }); auto sf = fut.share();std::move:std::thread t([f = std::move(fut)]{ f.get(); });[fut = std::move(fut)]() mutable { fut.get(); }如果 async 中的函数抛出异常,std::future::get() 不会返回值,而是直接重抛该异常(类型不变)。这是 std::future 的核心设
计之一,但容易忽略其传播时机。
get() 时抛出;后续调用仍报 no_state
wait(),异常不会触发,直到你调用 get()
get(),尤其在封装异步调用时:try { auto res = fut.get(); } catch (const std::exception& e) { /* 处理 */ }真正麻烦的是:一旦 std::future 被 move 出作用域,又没在析构前 get() 或 wait(),程序就可能卡死在析构点——这个行为静默且难以调试。