std::promise与std::future需通过get_future()显式配对,一 promise 仅可绑定一 future;set_value()触发wait()/get()返回,get()只可调用一次,promise析构前未设置值则get()抛broken_promise。

std::promise 和 std::future 怎么配对传递值?
它们不是自动绑定的,必须通过 std::promise::get_future() 显式获取对应 std::future,且只能调用一次。一旦获取,std::promise 和 std::future 就共享底层状态对象(通常叫 __state 或类似实现细节),后续对 std::promise::set_value() 的调用会触发 std::future::wait() 或 std::future::get() 返回。
常见错误现象:std::future 构造后未从同一 std::promise 获取,或重复调用 get_future() —— 后者会抛出 std::future_error(错误码为 std::future_errc::future_already_retrieved)。
- 一个
std::promise只能关联一个std::future;反之不成立(但多对一无意义,也不支持) - 不能把
std::promise拷贝给另一个线程,它不可拷贝;必须移动(std::move(p))或用指针/智能指针传递 -
std::future本身可移动,但移动后原对象变为无效状态(valid() == false)
为什么 set_value() 后 get() 不卡死,但 wait() 还要等?
因为 std::promise::set_value() 是“发信号”动作,它设置共享状态为 ready,并唤醒所有等待该状态的线程;而 std::future::get() 在返回前会隐式调用 wait(),再读取值 —— 所以它既同步又取值。但 wait() 只同步、不取值,适合只关心完成时机、不关心结果内容的场景(比如纯屏障)。
性能影响:如果值类型大且不需要立即使用,先 wait() 再 get() 可避免不必要的拷贝延迟(不过现代编译器常优化掉);若值小或必须立刻消费,直接 get() 更简洁。
立即学习“C++免费学习笔记(深入)”;
-
get()只能调用一次,第二次会抛std::future_error(std::future_errc::no_state) - 若 promise 被析构前未调用
set_value()、set_exception()或set_value_at_thread_exit(),则future::get()会抛std::future_error(std::future_errc::broken_promise) - 不要在 promise 所在线程里直接调用
future::get()—— 它会永远阻塞,除非 promise 在另一线程中设置
std::promise 能用来做纯信号同步吗?
可以,而且很常用。当只需要通知“某事已完成”,不传数据时,std::promise<void></void> 配合 std::future<void></void> 是轻量级选择。它的 set_value() 不带参数,get() 返回 void,语义清晰。
容易踩的坑:有人误以为 std::future<void>.wait()</void> 等价于 std::condition_variable + std::mutex,其实不然——std::future<void></void> 不支持超时等待(wait_for/wait_until 是有的,但 void 版本仍受限于底层实现是否真正支持),且无法重置、无法多次通知。
- 适合一次性同步点(如初始化完成、任务结束)
- 不适用于需要多次触发、或需响应中断/超时的场景
- 若需超时,必须用
std::future<t>::wait_for()</t>,但 void 类型下返回值仍是std::future_status,不能忽略
跨线程传递 promise/future 时要注意什么?
核心是生命周期管理:promise 必须活到被 set_value() 调用之后,future 必须活到 get()/wait() 返回之后。最安全的方式是用 std::shared_ptr<:promise>></:promise> 包裹 promise,在生产者和消费者之间共享所有权;future 通常由消费者独占持有,无需共享。
典型错误:把局部 std::promise 对象 move 进线程函数,但主线程函数返回后 promise 被析构,子线程再调用 set_value() 就是未定义行为。
- 推荐模式:在创建线程前 new 一个
std::promise,用std::shared_ptr管理;或直接用std::packaged_task替代手动配对 - 避免裸指针传递 promise/future,尤其不要让多个线程同时写同一个 promise(
set_value()非线程安全,仅保证对同一 promise 的多次 set 是互斥的) - future 的
wait()和get()是线程安全的,可被多个线程并发调用(但结果未定义:只有一个能成功取值,其余抛异常)
真正麻烦的从来不是怎么调用那几个函数,而是谁在什么时候销毁 promise、谁还在等着 future、以及有没有人忘了 set_value —— 这些问题不会报编译错误,但会让程序在某个负载下突然 hang 住或崩溃。









