You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Boost.Asio C++20协程中实现自定义可等待(awaitable)对象

错误根因

你编写的是标准C++20原生可等待体,但boost::asio::awaitable协程框架的promise类型自定义了await_transform规则,仅支持符合Asio异步操作模型的等待对象,不支持直接co_await自定义原生可等待体,因此触发类型转换报错。
同时你直接通过std::coroutine_handle<>::resume()恢复协程的逻辑也存在线程安全风险:如果你的响应回调运行在非Asio io_context调度线程,会直接在回调线程执行协程后续逻辑,可能引发数据竞争。

可行解决方案

使用Boost.Asio官方提供的async_initiate工具,将回调式API包装为符合Asio规范的异步操作,可天然兼容awaitable协程,同时自动处理执行器上下文绑定、异常传递等逻辑。

代码修改步骤

  1. 重写async_request包装逻辑:
#include <boost/asio/async_result.hpp>
#include <boost/asio/use_awaitable.hpp>

// 若编译器不支持C++20概念,可移除completion_token_for约束,直接写template <typename CompletionToken>
template <boost::asio::completion_token_for<void(response)> CompletionToken = boost::asio::use_awaitable_t<>>
auto async_request(client* cli, const request& r, CompletionToken&& token = {})
{
    return boost::asio::async_initiate<CompletionToken, void(response)>(
        [](auto completion_handler, client* cli, request req) {
            cli->send(req, [handler = std::move(completion_handler)](const response& resp) mutable {
                std::move(handler)(resp);
            });
        },
        token, cli, r
    );
}

这里为模板参数设置了use_awaitable作为默认 completion token,调用时不需要额外传参即可直接在awaitable协程中使用。

  1. 协程内调用逻辑:
boost::asio::awaitable<void> network::sts::client::connect()
{
    //...
    // 直接co_await即可,不需要额外传参
    auto res = co_await async_request(this, make_sts_connect());
    //...
}

额外注意事项

  • 如果你的响应回调可能抛出异常,需要在回调内捕获异常,并通过boost::asio::post将异常传递到协程执行上下文,避免直接触发std::terminate
  • 如果需要支持异步操作取消,可以在包装逻辑中集成Asio的取消槽机制,适配协程的自动取消逻辑

内容的提问来源于stack exchange,提问作者ACB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 13:48:05