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

使用asio::io_context::strand同步任务无输出,求正确实现方式

问题:使用Asio Strand同步任务无输出的解决方法

我尝试用strand同步完成处理程序,但未得到预期结果:不包装strand直接调用asio::post时,输出正常但任务不同步;用strand包装后完全没有输出。

最小可复现示例

#include <asio.hpp>
#include <thread>
#include <iostream>
#include <vector>
#include <random>

struct Task
{
    Task(int id, int wait_time) 
        : id_{id}
        , wait_time_{wait_time}
    {}

    void operator()()
    {
        std::cout << "Tast-" << id_ << " started. [" << std::this_thread::get_id() << "]" << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(wait_time_));
        std::cout << "Task-" << id_ << " finished after (" << wait_time_
                  << ") milliseconds. [" << std::this_thread::get_id() << "]" << std::endl;
    }
    int id_;
    int wait_time_;
};

int main()
{
    std::random_device rd;
    std::mt19937 engine(rd());
    std::uniform_int_distribution d(500, 2'000);

    asio::io_context ctx;
    asio::io_context::strand strand(ctx);

    std::vector<std::jthread> threads;
    auto count = 4;
    for (int i = 0; i < count; ++i)
    {
        threads.emplace_back([&]{ ctx.run(); });
    }

    for (int i = 0; i < count * 2; ++i)
    {
        asio::post(Task(i + 1, d(engine)));
        // asio::post(strand.wrap(Task(i + 1, d(engine))));  /* THIS DOESN'T PRODUCE ANY OUTPUT */
    }
    ctx.run();
}

无Strand时的输出

Tast-1 started. [17652]
Tast-7 started. [26096]
Tast-3 started. [56484]
Tast-8 started. [32000]
Tast-5 started. [Tast-6 started. [79448]
61340]Tast-2Tast-4 started. [55696]
 started. [84880]

Task-6 finished after (784) milliseconds. [79448]
Task-2 finished after (835) milliseconds. [84880]
Task-1 finished after (923) milliseconds. [17652]
Task-4 finished after (1281) milliseconds. [55696]
Task-3 finished after (1668) milliseconds. [56484]
Task-7 finished after (1763) milliseconds. [26096]
Task-8 finished after (1888) milliseconds. [32000]
Task-5 finished after (1982) milliseconds. [61340]

问题原因与修复方案

核心问题

你错误地使用了strand.wrap():将包装后的handler直接post到io_context,而非通过strand来投递任务。这种用法无法触发strand的串行调度逻辑,反而会导致任务无法被正确执行。

正确使用方式

有两种标准用法可以实现strand的同步效果:

  1. 直接通过strand的post方法投递任务(推荐,写法更简洁):
    asio::post(strand, Task(i + 1, d(engine)));
    
  2. 用strand.wrap()包装后,仍投递到strand:
    asio::post(strand, strand.wrap(Task(i + 1, d(engine))));
    

修复后的完整代码

#include <asio.hpp>
#include <thread>
#include <iostream>
#include <vector>
#include <random>

struct Task
{
    Task(int id, int wait_time) 
        : id_{id}
        , wait_time_{wait_time}
    {}

    void operator()()
    {
        std::cout << "Task-" << id_ << " started. [" << std::this_thread::get_id() << "]" << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(wait_time_));
        std::cout << "Task-" << id_ << " finished after (" << wait_time_
                  << ") milliseconds. [" << std::this_thread::get_id() << "]" << std::endl;
    }
    int id_;
    int wait_time_;
};

int main()
{
    std::random_device rd;
    std::mt19937 engine(rd());
    std::uniform_int_distribution d(500, 2'000);

    asio::io_context ctx;
    asio::io_context::strand strand(ctx);

    std::vector<std::jthread> threads;
    auto count = 4;
    for (int i = 0; i < count; ++i)
    {
        threads.emplace_back([&]{ ctx.run(); });
    }

    for (int i = 0; i < count * 2; ++i)
    {
        asio::post(strand, Task(i + 1, d(engine)));
    }
    ctx.run();
}

修复后效果

任务会严格串行执行,同一时间只有一个任务在运行,输出类似:

Task-1 started. [12345]
Task-1 finished after (800) milliseconds. [12345]
Task-2 started. [12345]
Task-2 finished after (1200) milliseconds. [12345]
...

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 13:35:17