std::future 和 std::promise 是 C++11 提供的单次值传递同步机制,用于异步任务结果传递;std::promise 设置值,std::future 获取值,二者配对且仅能各操作一次,不可拷贝,需配合移动语义使用。

std::future 和 std::promise 是 C++11 引入的、用于在线程间**单次传递一个值**的同步机制。它们不是通用消息队列,也不是替代 std::mutex 的工具,而是专为“我启动一个异步任务,稍后取它的返回值”这种场景设计的。
std::promise 和 std::future 必须配对使用,且只能消费一次
一个 std::promise 对象持有一个可写入的共享状态;调用 set_value()(或 set_exception())后,其关联的 std::future 就能通过 get() 读取结果。关键约束是:
-
std::future::get()只能调用一次,第二次会抛出std::future_error(错误码为std::future_errc::no_state或std::future_errc::future_already_retrieved) -
std::promise::set_value()也只能调用一次;重复调用会终止程序(std::terminate) -
std::promise和std::future之间通过移动语义转移共享状态,不能拷贝
常见误用:在多个线程里反复调用 get() 试图“轮询”,这会导致崩溃或未定义行为。
如何在线程间安全传递 int 值(最简可行示例)
典型模式是主线程创建 std::promise,把它的 std::future 移交给工作线程(或反过来),再由某一方负责设置值、另一方负责获取。注意:std::promise 本身不带线程安全保证,但它的 set_* 成员函数是线程安全的;std::future::get() 是线程安全的阻塞等待。
立即学习“C++免费学习笔记(深入)”;
int main() {
std::promise p;
std::future f = p.get_future(); // 此处转移共享状态
std::thread t([&p]() {
std::this_thread::sleep_for(std::chrono::seconds(1));
p.set_value(42); // 工作线程设置值
});
int result = f.get(); // 主线程阻塞等待并取值(自动 move)
t.join();
return result;
}
std::packaged_task 是更自然的封装方式
手动管理 std::promise 容易出错,尤其当你要传函数对象时。std::packaged_task 把可调用对象和配套的 std::promise 绑定在一起,构造时自动生成 std::future,调用时自动触发 set_value():
- 适用于“异步执行一个函数,并取其返回值”场景
- 支持 lambda、函数指针、成员函数等所有可调用类型
- 避免手动调用
set_value(),减少逻辑遗漏风险
int main() {
std::packaged_task task([]{ return 123; });
std::future f = task.get_future();
std::thread t(std::move(task));
int x = f.get(); // 阻塞直到线程执行完 task 并返回
t.join();
return x;
}
不要用 future/promise 替代线程安全容器或信号量
它不解决多生产者、多消费者、重复读写、流式数据等问题。例如:
- 想让线程 A 不断往缓冲区 push 数据,线程 B 不断 pop → 用
std::queue+std::mutex+std::condition_variable - 想通知线程 B “事件发生了”,但不传具体值 → 用
std::atomic或std::condition_variable - 想跨线程传字符串、vector 等大对象 → 注意移动语义,
std::future::get()返回的是右值引用,会自动 move
最常被忽略的一点:future 的阻塞等待(get()、wait())无法被中断,也没有超时重试的默认机制——如果 promise 永远不被 set,线程就永远卡住。生产环境务必配合 wait_for() 或 wait_until() 使用。











