C++中如何检查std::promise的结果是否已设置?
问题解答
截至C++20,std::promise确实没有提供直接检查是否已设置值的成员函数。针对你遇到的多线程回调重复触发、重复调用set_value抛异常的问题,这里有几种可行的替代方案:
1. 封装带原子状态标记的安全Promise
最可靠且性能友好的方式是给std::promise搭配一个原子布尔标记,封装成工具类来避免重复设置值。原子操作能保证多线程下的状态同步,且不会引入额外的异常开销:
#include <future> #include <atomic> template<typename T> class SafePromise { public: void set_value(const T& value) { // 原子CAS操作,确保只有第一次调用能成功设置值 bool expected = false; if (_is_set.compare_exchange_strong(expected, true, std::memory_order_acq_rel)) { _promise.set_value(value); } } std::future<T> get_future() { return _promise.get_future(); } private: std::promise<T> _promise; std::atomic<bool> _is_set{false}; };
在你的回调中使用这个类:
SafePromise<int> safe_promise; void c_library_callback(int result) { // 只有第一次调用会真正设置promise的值 safe_promise.set_value(result); }
主线程逻辑不变:等待future拿到结果后调用C库的取消订阅接口。这种方式把状态检查和设置封装在一起,后续代码变更时只要依赖这个工具类,就能降低出错概率。
2. 利用std::future的状态间接判断(局限场景)
如果你能在回调线程中安全访问到绑定的std::future,可以通过wait_for判断future是否已就绪,间接推断promise是否被设置:
// 注意:需用std::shared_ptr保证future在多线程中可安全访问 bool is_promise_set(std::shared_ptr<std::future<int>> future_ptr) { return future_ptr->wait_for(std::chrono::seconds(0)) == std::future_status::ready; } void c_library_callback(int result, std::shared_ptr<std::future<int>> future_ptr) { if (!is_promise_set(future_ptr)) { // 需确保回调能访问到对应的promise对象 promise.set_value(result); } }
但这种方式有明显局限:如果主线程已经调用过future.get(),wait_for也会返回ready,此时无法区分是已设置值还是已消费值,仅适用于特定场景。
3. 捕获std::future_error(最简方案)
虽然你希望避免异常,但std::future_error属于预期内的异常,且C++标准库对这类异常的实现开销很低。如果不想额外封装工具类,可以直接捕获异常:
std::promise<int> promise; void c_library_callback(int result) { try { promise.set_value(result); } catch (const std::future_error& e) { // 仅忽略"promise已被设置"的错误,其他异常重新抛出 if (e.code() != std::future_errc::promise_already_satisfied) { throw; } } }
这种方案代码量最小,适合快速解决问题,且仅在重复设置时触发异常,不会影响正常流程。
内容的提问来源于stack exchange,提问作者Janilson
相关产品推荐
相关产品推荐

