如何在Boost.Asio上下文内等待std::future完成?
实现WaitForFutureAsync的核心要求与代码方案
核心功能需求
要让std::future能在Asio的io_context中以类似定时器的异步方式等待,WaitForFutureAsync必须满足以下要求:
- 异步启动后立即返回,不阻塞调用线程
- 当
std::future就绪(完成/异常)时,回调函数必须在io_context::run()的线程中执行 - 与Asio的异步模型对齐,通过
error_code传递执行结果(成功、异常、取消等状态) - 兼容C17标准,不能使用C20及以上特性
实现思路
C++17的std::future没有原生异步通知机制,只能通过同步等待感知就绪状态。因此我们需要:
- 启动后台线程,同步等待
std::future就绪 - 当
future就绪后,通过Asio的post接口将回调投递到io_context的执行队列 - 捕获
future可能抛出的异常,转化为符合Asio规范的error_code
完整代码实现
#include <asio.hpp> #include <future> #include <thread> #include <functional> #include <iostream> void WaitForFutureAsync(asio::io_context& ctx, std::future<int> f, std::function<void(const std::error_code&)> callback) { // 启动后台线程等待future就绪 std::thread([ctx_ref = std::ref(ctx), f = std::move(f), callback = std::move(callback)]() mutable { std::error_code ec; try { // 同步等待future完成 f.wait(); // 获取结果,捕获可能的异常 (void)f.get(); ec = asio::error::success; } catch (const std::future_error&) { // 处理future被取消/异常的情况 ec = asio::error::operation_aborted; } catch (const std::exception&) { // 处理用户自定义异常 ec = asio::error::fault; } catch (...) { // 处理未知异常 ec = asio::error::unknown; } // 将回调投递到io_context线程执行 asio::post(ctx_ref.get_executor(), [callback = std::move(callback), ec]() { callback(ec); }); }).detach(); // 分离线程,让其自行完成生命周期 } // 测试用户提供的伪代码 void AddFutureToIoContext(std::future<int> f) { asio::io_context ctx; // 使用work_guard防止io_context在回调执行前退出 auto work_guard = asio::make_work_guard(ctx); WaitForFutureAsync(ctx, std::move(f), [&work_guard](const std::error_code& error){ std::cout << "The future has come"; if (error) { std::cout << " with error: " << error.message() << std::endl; } else { std::cout << " successfully." << std::endl; } // 释放work_guard,允许io_context退出 work_guard.reset(); }); ctx.run(); } // 测试入口 int main() { std::promise<int> p; auto future = p.get_future(); // 模拟异步任务 std::thread([p = std::move(p)]() mutable { std::this_thread::sleep_for(std::chrono::seconds(2)); p.set_value(42); // 标记future完成 // 若要测试异常情况,可替换为:p.set_exception(std::make_exception_ptr(std::runtime_error("test error"))); }).detach(); AddFutureToIoContext(std::move(future)); return 0; }
关键细节说明
- 移动语义:
std::future不可拷贝,必须通过std::move传递,确保资源所有权正确转移 - Work Guard:必须使用
asio::make_work_guard,否则io_context::run()会在没有待处理任务时立即退出,无法等待回调执行 - 线程安全:Asio的
post操作是线程安全的,后台线程可以安全地将回调投递到io_context - 异常转化:将
future的各种异常情况映射到Asio标准error_code,符合Asio的错误处理范式 - 线程生命周期:后台线程使用
detach(),无需主线程等待,其唯一职责是等待future并投递回调
内容的提问来源于stack exchange,提问作者Anders Brodin
相关产品推荐
相关产品推荐

