【问题标题】:boost::asio::io_service, std::thread, Cannot understand the result of codeboost::asio::io_service, std::thread, 无法理解代码的结果
【发布时间】:2020-03-23 18:07:55
【问题描述】:

我正在学习 boost::asio 库来编写 UDP 客户端和服务器,不幸的是我不知道这段代码的结果:

#include <boost/asio.hpp>
#include <thread>
#include <mutex>
#include <chrono>
#include <iostream>

int main() {
    boost::asio::io_service service;
    std::mutex mtx;

    for (int i = 0; i < 20; ++i)
    {
        service.post([i, &mtx]() {
            std::scoped_lock<std::mutex> lg(mtx);
            std::cout << '[' << std::this_thread::get_id()
                      << "] " << " Handler [" << i << "]" << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(1));
        });
    }

    std::vector<std::thread> pool;

    for(int i = 0; i < 4; i++)
        pool.emplace_back([&service]() { service.run(); });

    for (auto& thread : pool)
        if (thread.joinable())
            thread.join();
}

它在一个循环中发布 20 个处理程序,每个处理程序打印其标识符,然后休眠一秒钟。为了运行,我创建了向量,其中每个元素都运行 io_service。这段代码的结果:

[139801306236672]  Handler [0]
[139801306236672]  Handler [4]
[139801306236672]  Handler [5]
[139801306236672]  Handler [6]
[139801306236672]  Handler [7]
[139801306236672]  Handler [8]
[139801306236672]  Handler [9]
[139801306236672]  Handler [10]
[139801306236672]  Handler [11]
[139801306236672]  Handler [12]
[139801306236672]  Handler [13]
[139801306236672]  Handler [14]
[139801306236672]  Handler [15]
[139801306236672]  Handler [16]
[139801306236672]  Handler [17]
[139801306236672]  Handler [18]
[139801306236672]  Handler [19]
[139801185482496]  Handler [2]
[139801297843968]  Handler [3]
[139801289451264]  Handler [1]

我不知道,为什么用 1、2 和 3 索引的处理程序最终会像 2 - 3 - 1。我也尝试了 dispatch() 而不是 post() 方法,结果是一样的。有人能解释一下这里发生了什么吗?

【问题讨论】:

    标签: c++ boost pthreads c++17


    【解决方案1】:

    根据 asio 文档,异步完成处理程序只会从当前正在调用 service.run() 的线程中调用。您正在从多个线程调用service.run()。每个调用都会使处理程序出列并调用它。线程是由操作系统调度的,而将i=2 处理程序出队的线程恰好在将i=1 处理程序出队的线程之前调度。

    您的代码不会按原样对处理程序的执行施加任何顺序。如果您想要顺序调用处理程序,只需调用一次service.run()。在更复杂的场景中,您可以使用 asio strands 进行顺序调用。

    【讨论】:

      【解决方案2】:

      当您通过 asio 执行程序发布到线程池时,发布的作业不会以保证的顺序运行。您在输出中看到操作系统调度的不确定性。要修复作业的顺序,您需要以某种方式将一个作业的结束与下一个作业的开始同步。在 asio 中,当您具有这种依赖关系时,您可以拥有一份工作,只需从其内部发布下一个工作即可。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-03-28
        • 2011-06-16
        • 1970-01-01
        • 2017-09-17
        • 2012-11-26
        • 2011-12-18
        • 1970-01-01
        相关资源
        最近更新 更多