基于Boost 1.66.0,如何从boost::asio::post获取future?
让Boost Asio的
post返回future的方法 在Boost 1.66.0里,async_read这类异步操作能通过boost::asio::use_future返回future,是因为它们支持**完成令牌(Completion Token)**机制。而post本身是个“fire-and-forget”的函数,默认不返回future,但我们可以通过封装一个支持完成令牌的异步版本来实现相同效果。
核心思路:封装支持完成令牌的async_post
我们可以借助Boost Asio的async_initiate工具,把post包装成一个接受完成令牌的异步操作,这样就能直接用use_future作为令牌,让它返回future。
1. 无返回值的async_post
如果你只是想提交一个无返回值的任务,拿到future<void>来等待任务完成,用这个版本:
#include <boost/asio.hpp> #include <future> template <typename CompletionToken> auto async_post(boost::asio::io_context& io_context, CompletionToken&& token) { return boost::asio::async_initiate<CompletionToken, void()>( [&](auto&& completion_handler) { // 把完成处理程序提交到io_context boost::asio::post(io_context, std::forward<decltype(completion_handler)>(completion_handler)); }, token); }
使用示例:
boost::asio::io_context io_ctx; // 提交无返回值任务,拿到future<void> auto fut = async_post(io_ctx, boost::asio::use_future); // 运行io_context std::thread t([&](){ io_ctx.run(); }); // 等待任务完成 fut.get(); t.join();
2. 带返回值的async_post
如果你的任务有返回值,希望future能拿到结果(或捕获任务抛出的异常),可以用这个增强版:
#include <boost/asio.hpp> #include <future> #include <type_traits> template <typename Func, typename CompletionToken> auto async_post(boost::asio::io_context& io_context, Func&& func, CompletionToken&& token) { // 推导任务的返回类型 using ResultType = decltype(std::declval<Func>()()); return boost::asio::async_initiate<CompletionToken, void(ResultType)>( [&, func = std::forward<Func>(func)](auto&& completion_handler) mutable { boost::asio::post(io_context, [func = std::move(func), handler = std::forward<decltype(completion_handler)>(completion_handler)]() mutable { try { if constexpr (std::is_void_v<ResultType>) { // 无返回值任务:执行后调用无参完成处理程序 func(); handler(); } else { // 有返回值任务:把结果传递给完成处理程序 handler(func()); } } catch (...) { // 将异常传递给完成处理程序,use_future会在get()时抛出该异常 std::rethrow_exception(std::current_exception()); } }); }, token); }
使用示例:
boost::asio::io_context io_ctx; // 提交返回int的任务 auto fut = async_post(io_ctx, [](){ return 42; }, boost::asio::use_future); io_ctx.run(); // 获取结果并输出42 std::cout << fut.get() << std::endl;
为什么这个方案可行?
boost::asio::async_initiate是Asio用来构建自定义异步操作的工具,它会根据你传入的完成令牌(比如use_future)自动生成对应的返回值(这里就是future)。当你用use_future作为令牌时,Asio会创建一个promise并返回其关联的future;完成处理程序被调用时,会自动设置promise的结果(或异常)。
这个封装完全遵循Asio的异步操作模型,和async_read使用use_future的逻辑完全一致。
内容的提问来源于stack exchange,提问作者Chris Hunt
相关产品推荐
相关产品推荐

