std::promise与std::future必须成对使用,通过共享状态关联:promise负责单次设置值或异常(需用std::current_exception封装),future负责获取结果;仅可移动promise,重复set_*未定义,多future需用shared_future;wait_for/untill返回future_status枚举须显式判断;async默认策略不可靠,应显式指定launch::async或deferred。

std::promise 和 std::future 怎么配对使用
必须成对出现,且 std::promise 对象负责设置值(或异常),std::future 负责获取结果;两者通过共享状态(shared state)关联,不能跨线程随意拷贝 std::promise——它只允许移动。
-
std::promise一旦被移动走,原对象就处于“无效”状态,再调用set_value()会抛出std::future_error(错误码为std::future_errc::no_state) - 一个
std::promise只能调用一次set_value()或set_exception();重复调用会触发未定义行为(常见表现是程序崩溃或断言失败) - 如果想让多个
std::future等待同一个结果,得用std::shared_future,而不是反复从同一个std::promise调get_future()(后者每次返回的都是独立 future,但共享状态已绑定,第二次调用会失败)
std::future::wait_for() 和 wait_until() 返回值怎么判断
这两个函数不直接返回结果,而是返回 std::future_status 枚举,必须显式检查才能知道是否超时、就绪还是延后;忽略返回值就等于没做超时控制。
-
std::future_status::ready:结果已就绪,此时可安全调用get() -
std::future_status::timeout:等待超时,get()仍会阻塞(除非你再次检查) -
std::future_status::deferred:任务被延迟执行(仅当用std::async且带std::launch::deferred时出现),此时调用get()才真正执行函数
示例:
auto f = std::async(std::launch::async, []{ return 42; });<br>if (f.wait_for(std::chrono::milliseconds(10)) == std::future_status::ready) {<br> int x = f.get(); // 安全<br>}
std::async 启动策略选 deferred 还是 async
默认策略 std::launch::async | std::launch::deferred 表示“由实现决定”,但实际中多数编译器(如 GCC、Clang)在无负载时倾向 deferred,导致你以为开了新线程,其实还是同步执行——这是最常被忽略的性能陷阱。
立即学习“C++免费学习笔记(深入)”;
- 明确要异步,就写死
std::launch::async;否则可能卡主线程,且wait_for()永远返回ready -
deferred适合“可能根本不执行”的场景(比如日志写入,若日志级别关闭就不跑),但无法利用多核,也不满足真正的并发需求 - 混合策略下,
std::async可能复用线程池(MSVC)、也可能不复用(GCC),行为不可移植;生产环境建议避免依赖默认策略
std::promise 的异常传递为什么总崩
不是所有异常都能被 std::promise::set_exception() 正确捕获——必须用 std::current_exception() 包一层,否则传进去的是空异常指针,后续 get() 会直接 terminate。
- 正确写法:
p.set_exception(std::current_exception()); - 错误写法:
p.set_exception(e);(e 是 catch 块里的异常对象,类型不匹配) - 更安全的做法是统一用 lambda 包裹逻辑,在内部 try/catch 后调
set_value或set_exception,避免裸 throw 泄露到 promise 外
异步上下文里没有栈展开(stack unwinding)保证,异常不显式捕获并转成 std::exception_ptr,就等于没处理。










