Boost Asio:如何实现从yield返回后自动执行回调?
Boost Asio实现yield返回后自动执行回调的方案
Boost Asio原生的yield_context本身不直接支持自动执行回调的功能,但可以通过自定义包装yield上下文的方式实现需求,无需在每个异步操作后显式调用回调。
核心思路
封装原生yield_context,重载其operator()来捕获异步操作的完成时机,在调用原始yield的处理逻辑后自动插入自定义回调。
实现代码示例
#include <boost/asio.hpp> #include <boost/asio/spawn.hpp> #include <functional> #include <iostream> // 自定义带自动回调的yield上下文包装类 class YieldWithAutoCallback { public: YieldWithAutoCallback(boost::asio::yield_context yield, std::function<void()> callback) : yield_(std::move(yield)), auto_callback_(std::move(callback)) {} // 重载operator(),适配异步操作的handler签名 template <typename CompletionToken> auto operator()(CompletionToken&& token) { return boost::asio::bind_executor( yield_.get_executor(), [this, token = std::forward<CompletionToken>(token)](auto&&... args) mutable { // 先执行原生yield的回调逻辑,恢复协程 std::invoke(token, std::forward<decltype(args)>(args)...); // 自动执行自定义回调 if (auto_callback_) { auto_callback_(); } } ); } // 暴露原生yield的executor,满足Asio接口要求 auto get_executor() const noexcept { return yield_.get_executor(); } private: boost::asio::yield_context yield_; std::function<void()> auto_callback_; };
使用方式
在协程中创建自定义的yield上下文,替代原生yield即可:
void https_client(boost::asio::io_context& io_context, boost::asio::ssl::context& ssl_context) { boost::asio::spawn(io_context, [&](boost::asio::yield_context yield) { // 定义要自动执行的基础回调 auto base_callback = []() { std::cout << "异步操作完成,自动执行基础回调" << std::endl; }; // 创建带自动回调的yield上下文 YieldWithAutoCallback yield_with_cb(yield, base_callback); // 后续所有使用该上下文的异步操作,完成后都会自动触发回调 boost::asio::ssl::stream<boost::asio::ip::tcp::socket> stream(io_context, ssl_context); // 省略握手、连接等前置步骤... http::request<http::string_body> req(http::verb::get, "/", 11); req.set(http::field::host, "example.com"); req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); // 执行async_write,完成后自动触发base_callback http::async_write(stream, req, yield_with_cb); http::response<http::dynamic_body> res; boost::beast::flat_buffer buffer; // 执行async_read,完成后同样自动触发base_callback http::async_read(stream, buffer, res, yield_with_cb); }); }
注意事项
- 回调会在异步操作完成、协程恢复后执行,不会干扰异步操作的结果处理逻辑;
- 如果回调需要访问协程内的局部变量,需注意变量生命周期,避免悬空引用;
- 可根据需求扩展包装类,比如支持携带异步操作的错误码、结果等参数的回调。
内容的提问来源于stack exchange,提问作者Zohar81
相关产品推荐
相关产品推荐

