协程技术:如何在非协程感知库代码中调用async_*函数
解决方案:不修改接口前提下在底层函数中使用Asio协程
由于RequestContext的doSomething()是普通虚函数,无法直接改为协程函数,我们可以通过以下几种方案在不修改接口的前提下,在具体实现中使用co_await和异步操作:
方案一:启动独立协程执行异步逻辑(无需上层等待)
直接在doSomething()内部用boost::asio::co_spawn启动独立协程,异步操作会在后台由io_context调度执行,上层协程无需等待即可继续运行。适合不需要同步感知异步操作完成的场景。
修改后的AsyncRequestContext实现:
struct AsyncRequestContext : public RequestContext { boost::asio::io_context ioc; void doSomething() override { // 启动独立协程执行异步逻辑 boost::asio::co_spawn(ioc, [this]() -> boost::asio::awaitable<void> { boost::asio::deadline_timer timer(ioc); timer.expires_from_now(boost::posix_time::seconds(5)); co_await timer.async_wait(boost::asio::use_awaitable); // 可继续添加其他co_await异步操作 std::cout << "异步操作完成\n"; }, boost::asio::detached); } };
方案二:让上层协程等待异步操作完成
如果需要上层协程等待doSomething()内的异步操作完成后再继续执行,可以在具体实现类中保存一个awaitable任务,在上层协程中通过co_await等待该任务完成。这种方式保持了协程的同步语义,符合Asio协程的设计风格。
修改后的代码:
struct AsyncRequestContext : public RequestContext { boost::asio::io_context ioc; // 保存待执行的异步任务 boost::asio::awaitable<void> pending_task_; void doSomething() override { // 将异步逻辑包装为awaitable任务 pending_task_ = [this]() -> boost::asio::awaitable<void> { boost::asio::deadline_timer timer(ioc); timer.expires_from_now(boost::posix_time::seconds(5)); co_await timer.async_wait(boost::asio::use_awaitable); std::cout << "异步操作完成\n"; }(); } }; // main中的协程修改为: boost::asio::co_spawn( rctx.ioc, [&rctx]() -> boost::asio::awaitable<void> { middle(rctx); // 等待doSomething中启动的异步任务完成 co_await rctx.pending_task_; co_return; }, boost::asio::detached);
方案三:手动挂起/恢复上层协程(不推荐常规使用)
通过捕获上层协程的句柄,在doSomething()中手动挂起协程,待异步操作完成后恢复。这种方式无需上层协程额外等待,但需要手动管理协程生命周期,存在空指针、重复挂起/恢复等风险,仅在特殊场景下使用。
修改后的代码:
struct AsyncRequestContext : public RequestContext { boost::asio::io_context ioc; // 保存当前调用的协程句柄 boost::asio::coroutine_handle<> current_coro_; void doSomething() override { boost::asio::deadline_timer timer(ioc); timer.expires_from_now(boost::posix_time::seconds(5)); // 异步回调中恢复协程 timer.async_wait([this](const boost::system::error_code& ec) { if (!ec && current_coro_) { current_coro_.resume(); } }); // 挂起当前协程,等待异步操作完成 current_coro_.suspend(); // 协程恢复后继续执行后续逻辑 std::cout << "异步操作完成\n"; } }; // main中的协程修改为: boost::asio::co_spawn( rctx.ioc, [&rctx]() -> boost::asio::awaitable<void> { // 获取当前协程句柄并保存到上下文 rctx.current_coro_ = co_await boost::asio::this_coro::coroutine; middle(rctx); co_return; }, boost::asio::detached);
内容的提问来源于stack exchange,提问作者SunkistHH
相关产品推荐
相关产品推荐

