boost::asio::io_service, std::thread, 无法理解代码的结果
boost::asio::io_service, std::thread, Cannot understand the result of code
我正在学习 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();
}
它 post 在一个循环中有二十个处理程序,每个处理程序都打印其标识符,然后休眠一秒钟。为了 运行,我创建了向量,其中每个元素 运行s 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 执行程序 post 到线程池时,posted 作业不会 运行 保证顺序。您在输出中看到 OS 调度不确定性。要固定作业的顺序,您需要以某种方式将一个作业的结尾与下一个作业的开头同步。在 asio 中,当你有这种依赖时,你可以从内部找到一份工作 post 下一份工作。
根据 asio 文档,异步完成处理程序只会从当前正在调用 service.run()
的线程中调用。您正在从多个线程调用 service.run()
。每次调用都会使处理程序出列并调用它。线程由 OS 调度,而使 i=2
处理程序出列的线程恰好在使 i=1
处理程序出列的线程之前被调度。
您的代码没有按原样对处理程序的执行强加任何顺序。如果要顺序调用处理程序,只需调用 service.run()
一次。在更复杂的场景下,可以使用asio strands进行顺序调用。
我正在学习 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();
}
它 post 在一个循环中有二十个处理程序,每个处理程序都打印其标识符,然后休眠一秒钟。为了 运行,我创建了向量,其中每个元素 运行s 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 执行程序 post 到线程池时,posted 作业不会 运行 保证顺序。您在输出中看到 OS 调度不确定性。要固定作业的顺序,您需要以某种方式将一个作业的结尾与下一个作业的开头同步。在 asio 中,当你有这种依赖时,你可以从内部找到一份工作 post 下一份工作。
根据 asio 文档,异步完成处理程序只会从当前正在调用 service.run()
的线程中调用。您正在从多个线程调用 service.run()
。每次调用都会使处理程序出列并调用它。线程由 OS 调度,而使 i=2
处理程序出列的线程恰好在使 i=1
处理程序出列的线程之前被调度。
您的代码没有按原样对处理程序的执行强加任何顺序。如果要顺序调用处理程序,只需调用 service.run()
一次。在更复杂的场景下,可以使用asio strands进行顺序调用。