std::promise不可跨线程传递,因其不可复制且非线程安全;正确做法是主线程创建promise并移动future给子线程,由promise所在线程调用set_value(),多线程等待需用shared_future。

std::promise 不能直接在线程间传递
你不能把 std::promise 对象本身(比如通过值或引用)跨线程传给另一个线程去 set_value(),因为 std::promise 是**不可复制(non-copyable)且非线程安全的**。一旦某个线程调用了它的 set_value()、set_exception() 或析构,其他线程再访问它就会导致未定义行为。
正确做法:用 std::promise + std::future 配对 + 线程安全传递 future
核心思路是:在创建线程前,先构造 std::promise,拿到对应的 std::future,然后把 std::future **移动**给接收线程(或存储起来),而把 std::promise 留在能安全调用 set_value() 的线程里(通常是生产者线程)。注意:std::future 是可移动的,且 get() 是线程安全的阻塞等待操作。
常见模式:
- 主线程创建
std::promise<int></int>,获取std::future<int></int> - 把
std::future移动进子线程(例如作为参数传入 lambda),子线程调用get()等待结果 - 主线程(或其他线程)在合适时机调用
promise.set_value(42)
示例:
std::promise<int> p;
std::future<int> f = p.get_future();
std::thread t([&p]() {
// 模拟耗时工作
std::this_thread::sleep_for(1s);
p.set_value(123); // 只有这一个线程调用 set_value
});
t.detach();
// 主线程可以等结果(也可交给其他线程等)
int res = f.get(); // 阻塞直到 set_value 被调用
</int></int>
多个线程等待同一个结果?用 std::shared_future
如果多个线程都需要读取同一个 promise 的结果,不能共享同一个 std::future(它只支持 move,不支持 copy)。必须用 std::shared_future —— 它是线程安全的、可拷贝的封装,底层共享同一状态。
转换方式:
- 从
std::future调用.share()得到std::shared_future - 之后可拷贝给任意数量的线程,每个线程都能安全调用
get()
注意:所有 shared_future 实例都等待同一个 set_value,且首次 get() 后续调用会立即返回(值已就绪)。
容易踩的坑:promise 生命周期 & 多次 set
std::promise 的生命周期必须**长于**任何对其 set_value() 的调用;一旦 promise 被析构,再调用 set_value() 会抛出 std::future_error(错误码 std::future_errc::no_state)。
另外,set_value() 只能调用一次。重复调用会抛出 std::future_error(错误码 std::future_errc::promise_already_satisfied)。没有内置机制防止误调,得靠逻辑保证 —— 常见做法是用 std::atomic_bool 标记是否已设置,或封装一层 guard。
真正难处理的是:promise 所在线程提前退出、异常未捕获、或忘记调用 set_value / set_exception —— 此时等待的 future::get() 会永远阻塞。线上代码务必确保无论路径如何,promise 都被满足(建议用 RAII 封装或 try/catch + set_exception)。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











