
std::future.wait() 和 std::future.get() 到底该用哪个?
wait() 只阻塞等待完成,不取值;get() 阻塞并返回结果,且只能调用一次——第二次调用会抛出 std::future_error(错误码为 std::future_errc::no_state)。
常见错误现象:在循环里反复调用 get(),或没检查 future 是否有效就直接 get(),结果程序崩溃或未定义行为。
使用场景:
- 仅需确认任务结束(比如等所有子线程完成),用
wait() - 需要获取返回值,且确定只取一次,用
get() - 若不确定是否已调用过
get(),先用valid()检查
auto fut = std::async([]{ return 42; });
if (fut.valid()) {
int val = fut.get(); // OK
// fut.get(); // ❌ 再调一次就 crash
}
std::future 被移动后原对象还安全吗?
移动后原 std::future 对象变为“无效状态”,valid() 返回 false,再调用 get() 或 wait() 会抛异常。
立即学习“C++免费学习笔记(深入)”;
容易踩的坑:
- 把
std::future当普通对象传值,却忘了它默认是移动语义(比如放进std::vector<:future>></:future>后遍历时,不小心移动了) - 在 lambda 捕获中用
[fut = std::move(fut)]后,原fut就废了,但后续代码还在用
参数差异:所有接收 std::future 的函数(如 std::thread 构造、std::packaged_task 绑定)都会触发移动,不是拷贝。
std::future<int> f1 = std::async([]{ return 1; });
std::future<int> f2 = std::move(f1); // f1 now invalid
// f1.get(); // ❌ throws std::future_error
多个 future 怎么高效等待完成?别手写轮询
std::future_status::timeout + wait_for() 手动轮询效率低、易出错,且无法响应任意一个完成——应该用 std::experimental::when_any(C++17 起标准库无原生支持),或更现实的做法:
- C++20 起可用
std::jthread+std::stop_token配合手动协调,但 still no built-in any/all - 实际项目中推荐:用
std::condition_variable+ 共享状态,或改用第三方库(如 folly::SemiFuture、boost::fibers::future) - 最轻量方案:把多个
std::future存进std::vector,用wait_for(1ms)轮询(仅限简单场景,注意 CPU 占用)
性能影响:频繁 wait_for(std::chrono::milliseconds(0)) 几乎等价于忙等,慎用。
std::async 默认启动策略坑得最多
std::async 默认用 std::launch::async | std::launch::deferred,编译器可自由选择同步还是异步执行——这意味着你写的“异步”代码,可能在调用 get() 时才真正执行,甚至不新开线程。
常见错误现象:
- 以为
std::async一定并发,结果压测时发现串行执行、CPU 利用率低 - 在调试时加断点,发现 lambda 根本没进,直到
get()才运行(deferred 模式)
正确做法:显式指定策略:
-
std::launch::async:强制新线程(最接近直觉) -
std::launch::deferred:延迟调用,等get()或wait()时才执行(类似惰性求值)
// ❌ 不确定行为
auto f = std::async([]{ heavy_work(); });
<p>// ✅ 明确要并发
auto f = std::async(std::launch::async, []{ heavy_work(); });</p>多线程协作时,std::future 本身不提供线程安全的多次访问能力,它的设计就是“一次性消费”。如果需要多次读取结果,得自己包一层共享状态(比如 std::shared_ptr + std::mutex),而不是指望 std::future 做这件事。










