boost::asio::io_service,std::thread,无法理解代码的结果



我正在学习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();
}

它在一个循环中发布二十个处理程序,每个处理程序打印自己的标识符,然后休眠第二个。为了运行,我创建了vector,其中每个元素都运行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((,结果是一样的。有人能解释一下这里发生了什么吗?

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

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

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

最新更新