Boost.Asio中awaitable operator||定时器到期未返回问题咨询
问题描述
在Boost.Asio 1.81.0环境下,以下代码的run()函数期望通过operator||同时等待async_initiate返回的awaitable和2秒超时定时器,按预期定时器到期后协程应继续执行,但实际场景中(示例故意未调用async_initiate的handler,对应网络包未到达的情况),协程始终卡在co_await处。已知operator||会等待第一个成功完成的awaitable,定时器本应无错误完成,此现象不符合预期。
#include <boost/asio/any_completion_handler.hpp> #include <boost/asio/any_io_executor.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/co_spawn.hpp> #include <boost/asio/detached.hpp> #include <boost/asio/experimental/awaitable_operators.hpp> #include <boost/asio/io_context.hpp> #include <boost/asio/ip/udp.hpp> #include <boost/asio/steady_timer.hpp> #include <boost/asio/use_awaitable.hpp> #include <iostream> namespace asio = boost::asio; using namespace asio::experimental::awaitable_operators; // 仅用于保持io_context处于忙碌状态 asio::awaitable<void> busy() { auto exec = co_await asio::this_coro::executor; using asio::ip::udp; auto socket = udp::socket(exec, udp::endpoint(udp::v4(), 40000)); uint8_t msg[1024]; std::cout << "reading from socket...\n"; co_await socket.async_receive(asio::buffer(msg), asio::use_awaitable); } std::optional<asio::any_completion_handler<void(int)>> stored; asio::awaitable<void> run() { std::cout << "run() called\n"; auto exec = co_await asio::this_coro::executor; asio::steady_timer timer{exec, std::chrono::seconds(2)}; auto initiate = [&]([[maybe_unused]] asio::any_completion_handler<void(int)> handler) { // 故意不调用handler // 将handler存入stored是为了排除handler析构带来的副作用 stored = std::move(handler); }; co_await (asio::async_initiate<const asio::use_awaitable_t<>, void(int)>(initiate, asio::use_awaitable) || timer.async_wait(asio::use_awaitable)); std::cout << "done\n"; } int main() { asio::io_context io; asio::co_spawn(io, busy, asio::detached); asio::co_spawn(io, run, asio::detached); io.run(); }
问题分析与解决
核心原因
问题源于async_initiate的模板参数与传入的use_awaitable类型不匹配:
- 代码中指定
async_initiate的第一个模板参数为const asio::use_awaitable_t<>,但实际传入的use_awaitable是非const的asio::use_awaitable_t<>实例,这种类型不匹配导致Boost.Asio内部生成的awaitable处于异常状态。 - 当定时器到期时,
operator||尝试取消另一个awaitable,但因该awaitable状态异常,取消逻辑无法生效,最终协程被卡在co_await处无法继续执行。
修复方案
只需移除async_initiate模板参数中的const限定,使其与传入的use_awaitable类型一致:
co_await (asio::async_initiate<asio::use_awaitable_t<>, void(int)>(initiate, asio::use_awaitable) || timer.async_wait(asio::use_awaitable));
或者更简洁地省略模板参数,让Boost.Asio自动推导正确类型:
co_await (asio::async_initiate(initiate, asio::use_awaitable) || timer.async_wait(asio::use_awaitable));
验证效果
修改后,定时器到期时operator||会正确识别第一个完成的awaitable(定时器),触发协程继续执行并输出done,即使async_initiate的handler未被调用,协程也不会再卡住。
内容的提问来源于stack exchange,提问作者dvd
相关产品推荐
相关产品推荐

