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 来设值。