std::future.get() 会阻塞直到结果就绪,且只能调用一次;若任务出错则抛异常,重复调用或无效状态会触发 std::future_errc::no_state 异常;建议先用 wait_for(0s) 检查就绪再 get,并捕获 std::future_error 和 std::exception。

std::future.get() 会阻塞,直到结果就绪
调用 get() 是最直接的取值方式,但它会永久阻塞当前线程,直到关联的 std::promise 或异步任务完成。如果任务出错,get() 会抛出异常(比如 std::future_error 或 promise 设置的异常)。
常见错误是反复调用 get():每个 std::future 只能调用一次 get(),第二次调用会触发 std::future_errc::no_state 异常。
- 必须确保 future 对象仍持有有效状态(未被 move 走、未被 get 过)
- 若不确定任务是否完成,先用
wait_for(std::chrono::seconds(0))检查,再决定是否 get - 捕获
std::exception和std::future_error两种异常更稳妥
auto fut = std::async([]{ return 42; });
try {
int x = fut.get(); // ✅ 正确:一次取值
} catch (const std::future_error& e) {
// 处理 no_state、broken_promise 等
} catch (const std::exception& e) {
// 处理 async 中抛出的异常
}
std::future.wait_for() 和 wait_until() 用于带超时的等待
这两个函数不取值,只等待并返回状态,适合避免无限阻塞。区别在于:前者用相对时长(如 std::chrono::milliseconds(100)),后者用绝对时间点(如 std::chrono::system_clock::now() + 100ms)。
返回值是 std::future_status 枚举:ready、timeout 或 deferred(仅对 std::launch::deferred 启动策略有效)。
立即学习“C++免费学习笔记(深入)”;
-
wait_for(0s)是常用轮询手段,等价于“非阻塞检查是否就绪” - 注意
deferred状态下,任务实际还没执行,调用get()才真正运行 - 超时后不能直接
get()—— 必须先确认是ready状态,否则仍会阻塞
auto fut = std::async(std::launch::async, []{ std::this_thread::sleep_for(200ms); return 99; });
if (fut.wait_for(100ms) == std::future_status::ready) {
std::cout << fut.get(); // ✅ 安全
} else {
std::cout << "still running\n";
}
std::shared_future 支持多次 get()
原始 std::future 是可移动不可复制的,一旦 move 给另一个变量或调用 get(),原对象就失效。需要共享结果时,必须转成 std::shared_future。
它通过引用计数管理底层状态,允许多个实例同时调用 get() 或 wait_for(),且互不影响。
- 只能从 valid 的
std::future构造(move 构造),不能直接从std::async返回 - 构造后原
future失效,不能再用 - 多线程环境下,多个
shared_future实例并发get()是安全的
auto fut = std::async([]{ return "hello"; });
std::shared_future<std::string> sf{std::move(fut)}; // ✅ 转换
auto sf2 = sf; // ✅ 复制
std::thread t1([&]{ std::cout << sf.get(); }); // ✅
std::thread t2([&]{ std::cout << sf2.get(); }); // ✅
std::async 启动策略影响 future 行为
std::async 默认使用 std::launch::async | std::launch::deferred 策略,这意味着实现可自由选择立即执行或延迟执行。这会导致 wait_for(0s) 返回 deferred 而不是 timeout 或 ready,进而让逻辑难以预测。
明确指定策略更可靠:
-
std::launch::async:强制新开线程,wait_for(0s)不会返回deferred -
std::launch::deferred:任务在首次get()或wait()时才同步执行,此时wait_for总返回deferred - 混合策略下,
deferred可能掩盖性能问题——你以为异步,其实没跑
真正要异步执行,就显式写 std::async(std::launch::async, ...);否则默认行为在不同编译器/标准库上表现可能不一致。


















