Reputation: 37
I am learning boost::asio library to write UDP client and server and unfortunately I have no idea about results of this code:
#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();
}
It posts twenty handlers in a loop, where each prints its identifier and then sleeps for second. To run I create vector, where every element runs io_service. The result of this code:
[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]
I have no idea, why handlers indexed with 1, 2 and 3 end up like 2 - 3 - 1. I have tried also dispatch() instead of post() method and the result is the same. Can someone explain what happens here?
Upvotes: 0
Views: 641
Reputation: 1201
According to asio documentation, asynchronous completion handlers will only be called from threads that are currently calling service.run()
. You are calling service.run()
from multiple threads. Each call will dequeue a handler and call it. Threads are scheduled by the OS, and it just happened that the thread which dequeued the i=2
handler was scheduled before the thread which dequeued the i=1
handler.
Your code does not impose any order on the execution of handlers as it is. If you want sequential invocation of handlers, just call service.run()
once. In a more complex scenario, you can use asio strands for sequential invocation.
Upvotes: 1
Reputation: 1009
When you post to a thread pool through an asio executor, the posted jobs do not run in guaranteed order. You are seeing OS scheduling non-determinism in the output. To fix the ordering of the jobs, you need to synchronize the end of one job to the beginning of the next in some way. In asio, when you have that kind of a dependency, you can have a job just post the next job from within itself.
Upvotes: 0