future 和 promise 是用于线程间安全传递单个计算结果的异步通信工具,非线程启动机制;promise 单次写入、future 单次读取,通过共享状态关联,不可拷贝但可移动。

future 和 promise 是一对配合使用的异步通信工具
它们不是用来“启动线程”的,而是在线程之间安全传递单个计算结果的桥梁。一个线程用 promise 设置值,另一个线程用 future 等待并获取该值。核心约束是:每个 promise 只能调用一次 set_value()(或 set_exception()),否则抛出 std::future_error(错误码为 std::future_errc::promise_already_satisfied)。
-
std::promise持有写权限,负责“发信号”;std::future持有读权限,负责“收信号” - 两者通过共享状态(shared state)关联,通常由
promise.get_future()获取对应future - 不能拷贝
future或promise,但可以移动(std::move) - 如果
future被析构而没人调用get(),且promise未被满足,程序不会崩溃,但该结果永久丢失
如何避免 future.wait() 阻塞主线程
直接调用 future.wait() 会阻塞当前线程直到结果就绪,这在 GUI 或响应式系统中不可接受。更实用的方式是轮询或超时等待:
- 用
future.wait_for(std::chrono::milliseconds(10)) == std::future_status::ready做非阻塞检测 - 用
future.wait_until(std::chrono::steady_clock::now() + std::chrono::seconds(2))设定绝对截止时间 - 真正异步响应应结合
std::async或手动线程 + 回调,future本身不提供回调机制 - 注意:
wait_for和wait_until返回std::future_status::timeout时不抛异常,但后续调用get()仍会阻塞到就绪
promise.set_value() 必须在 shared state 销毁前调用
如果 promise 对象先于关联的 future 被销毁,且尚未调用 set_value() 或 set_exception(),则其 shared state 进入“broken”状态。此时 future.get() 会立即抛出 std::future_error(错误码为 std::future_errc::broken_promise)。
- 常见陷阱:把
promise声明在局部作用域,又在线程中异步调用set_value(),但主线程已退出作用域导致promise析构 -
解决方法:将
promise包装进std::shared_ptr,确保生命周期覆盖异步写入过程 - 或者改用
std::packaged_task,它自动管理 promise 生命周期,并可绑定到任意可调用对象
与 std::async 的关系:别混用,也别替代
std::async 内部封装了 promise/future,但它还负责线程调度和延迟策略(std::launch::async 或 std::launch::deferred)。你不能用 async 替代手动管理的 promise——比如无法从 async 返回的 future 反向拿到 promise 来设值。
立即学习“C++免费学习笔记(深入)”;
- 需要“主动触发结果”的场景(如 I/O 完成、信号到达、用户输入),必须用
promise - 只需要“异步执行函数并取返回值”,优先用
std::async,简洁且不易出错 -
std::async默认可能延迟执行(取决于实现和 flag),而手动promise+ 线程是完全可控的 - 多个线程向同一个
future写入?不行。一个promise只能有一个写入端,这是设计前提
最易被忽略的一点:shared state 的内存模型。即使你用 promise.set_value() 写入一个 int,它对 future.get() 的可见性由 future 的同步语义保证,不需要额外加 std::atomic 或锁——但如果你在 set_value() 前修改了外部变量,那些修改不一定对读线程可见,这点常被误认为是 future 的问题。










