c++的std::promise和std::future如何实现线程间通信? (异步任务返回值)

11次阅读

std::promise 和 std::future 是单次值传递的同步契约:一设一取,自动阻塞,不可重用、无超时、不支持多写,set_value 仅能调用一次,get() 为消费型操作,多次调用非法。

c++的std::promise和std::future如何实现线程间通信? (异步任务返回值)

std::promise 和 std::future 不是“通信机制”,而是**单次值传递的同步契约**:一个线程设值(set_value),另一个线程取值(get),中间自动阻塞等待。它不支持多次传值、也不支持取消或超时重试——别当 channel 用。

std::promise::set_value 必须且只能调用一次

这是最常踩的坑。重复调用 set_value 会抛出 std::future_error,错误码为 std::future_errc::promise_already_satisfied

  • 多个线程试图写同一个 std::promise?必须加锁,或改用 std::atomic + 标志位判断
  • 异步任务可能失败?用 set_exception 替代 set_value,否则 future.get() 会直接 rethrow
  • 忘记调用 set_valueset_exceptionfuture.get() 将永远阻塞(无超时)

std::future::get() 会移动并销毁内部状态

get() 是“消费型”操作:首次调用后,std::future 对象进入无效状态(valid() == false),再次调用 get() 抛出 std::future_errorstd::future_errc::no_state)。

  • 不要保存 std::future 多次调用 get() —— 它不是缓存,是一次性取货单
  • 需要共享结果?用 std::shared_future,它支持多次 get(),底层引用同一状态
  • 想非阻塞检查是否就绪?用 wait_for(std::chrono::seconds(0)) == std::future_status::ready

std::promise/std::future 不自带线程安全,但状态对象是线程安全的

std::promise 对象本身(如成员函数 get_future())不是线程安全的;但其关联的共享状态(由 std::futurestd::promise 共同持有)对 set_value/get 是线程安全的。

立即学习C++免费学习笔记(深入)”;

  • std::promise 只能被一个线程调用 set_valueset_exception —— 多线程写需外部同步
  • std::futureget()wait_for() 可在任意线程安全调用
  • 别把同一个 std::promise 对象传给多个线程去 get_future() —— 每个 get_future() 返回新 std::future,但共享状态只有一个
std::promise prom; std::future fut = prom.get_future();  std::thread t([&prom]() {     std::this_thread::sleep_for(std::chrono::seconds(1));     prom.set_value(42); // OK: 唯一写入点 }); t.detach();  // 主线程中: int val = fut.get(); // 阻塞直到 set_value,然后返回 42 // fut.get(); // ❌ runtime error: no_state

真正容易被忽略的是:这个契约没有超时语义,也没有重试路径;一旦 promise 被遗弃(未 set),future 就成了死锁源。生产环境建议用 std::packaged_task 包装可执行体,或直接上 std::async,它们自动管理 promise 生命周期。

text=ZqhQzanResources