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

Boost.Asio协程同时使用concurrent_channel与steady_timer时挂起问题

Boost.Asio协程结合steady_timer与concurrent_channel时部分协程卡在async_wait的问题

问题根源

你遇到的问题核心是**experimental::concurrent_channel的close操作与子协程async_receive的竞态,加上协程调度的不确定性**,在高并发场景下导致部分子协程无法及时触发timer重置,进而让父协程卡在co_await timer->async_wait。

具体细节:

  • 父协程创建channel后立即调用close(),随后挂起等待timer;
  • 子协程通过co_spawn异步启动,其async_receive操作可能因io_context任务队列积压,在channel关闭后很久才被调度执行;
  • 极端情况下,experimental版本的concurrent_channel可能存在高并发下的唤醒遗漏,导致子协程的async_receive无法完成,进而无法执行timer重置,父协程永久挂起。

你尝试的timer线程安全包装无效,因为问题根源不在timer的线程安全,而在于channel与协程调度的交互。

解决方案

方案1:替换experimental::concurrent_channel为更可靠的机制

如果业务逻辑只是需要触发子协程执行timer重置,完全可以去掉channel,改用asio::post直接触发子协程逻辑:

asio::co_spawn(
    ioc,
    [&, timer]() -> asio::awaitable<void> {
        asio::co_spawn(
            ioc,
            [timer]() -> asio::awaitable<void> {
                timer->expires_after(std::chrono::seconds{});
                co_return;
            },
            asio::detached);

        boost::system::error_code ec;
        co_await timer->async_wait(asio::redirect_error(asio::use_awaitable, ec));
        ++done;
        countRunning.count_down();
        co_return;
    },
    asio::detached);

方案2:确保子协程的receive操作在channel关闭前已提交

如果必须使用channel,可以添加同步机制,让父协程等待子协程开始接收后再关闭channel:

asio::co_spawn(
    ioc,
    [&, timer]() -> asio::awaitable<void> {
        asio::experimental::concurrent_channel<void(boost::system::error_code, double)> c(ioc, 1);
        boost::latch receiveStarted(1);

        asio::co_spawn(
            ioc,
            [&, timer]() -> asio::awaitable<void> {
                boost::system::error_code ec;
                receiveStarted.count_down(); // 通知父协程已开始接收
                co_await c.async_receive(asio::redirect_error(asio::use_awaitable, ec));
                timer->expires_after(std::chrono::seconds{});
                co_return;
            },
            asio::detached);

        receiveStarted.wait(); // 等待子协程开始接收
        boost::system::error_code ec;
        c.close();
        co_await timer->async_wait(asio::redirect_error(asio::use_awaitable, ec));
        ++done;
        countRunning.count_down();
        co_return;
    },
    asio::detached);

方案3:等待子协程完成后再等待timer

让父协程先等待子协程执行完毕,确保timer已被重置后再进入等待:

asio::co_spawn(
    ioc,
    [&, timer]() -> asio::awaitable<void> {
        asio::experimental::concurrent_channel<void(boost::system::error_code, double)> c(ioc, 1);

        // 用use_awaitable获取子协程的awaitable,而非detached
        auto child_task = asio::co_spawn(
            ioc,
            [&, timer]() -> asio::awaitable<void> {
                boost::system::error_code ec;
                co_await c.async_receive(asio::redirect_error(asio::use_awaitable, ec));
                timer->expires_after(std::chrono::seconds{});
                co_return;
            },
            asio::use_awaitable);

        boost::system::error_code ec;
        c.close();
        co_await child_task; // 等待子协程完成timer重置
        co_await timer->async_wait(asio::redirect_error(asio::use_awaitable, ec));
        ++done;
        countRunning.count_down();
        co_return;
    },
    asio::detached);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 14:57:02