Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does boost::asio::io_service prioritize work?

I am using boost::asio::io_service to manage some asynchronous TCP communication. That means I create a boost::asio::ip::tcp::socket and give the io_service to it. When I start the communication it goes schematically like this:

Async Resolve -> Callback -> Async Connect -> Callback -> Async Write -> Callback -> Async Read

I ommitted parts like resolve and bind. Just assume the Socket has been bound to a port and the hostname is resolved ( so connect meaning establishing the real connection to the endpoint )

Now the point is that I may start several Async Connections with the same io_service object. This means for example, that while in my io_service thread the program is about to Async Write some data, the main thread will call Async Resolve with on Socket ( but with the same io_service ). This means that my io_service now has some parallel work to do - what I'd like to know is how it will prioritize the work?

For example it go like this

Main Thread              |      io_service Thread
-------------------------+-----------------------------------------------
SocketA->Async Connect   |
//Some other Stuff       |     SocketA->Callback from Async Connect
                         |     SocketA->Async Write
SocketB->Async Connect   |      
                         |     --> ?

Now at this point I have to admit I am not quite sure how the io_service works. In the fourth line there are now two different asynchronous functions which needs to be executed.

Is io_service capable of doing the Async Connect and the Async Write simultaneously? If that is the case it is clear that always the callback from the function which is finished first will be called.

If the io_service is not capable of doing so, in which order will it do the work? If SocketA Async Write will be called first, it's callback will also be called first. Actually there will be always work until the whole operation on SocketA is finished.

EDIT :

According to ereOns comment I try to make my question a bit more precise:

From the view of the io_service thread - is the SocketA Async Connect call asynchronous or synchronous? From the view of my main thread it is of course asynchronous ( it just dispatches the command and then goes on ). But in the io_service thread will this specific Connect call block other operations?

In other words: Is one single io_service capable of Connecting to one Socket while it is reading on another?

Another example would be if I just call 2 Async Connect in my main function right after each other:

SocketA->AsyncConnect();
SocketB->AsyncConnect();

Let's say the Host from SocketA is a bit slow and it takes it two seconds to answer. So while SocketA is trying to connect would SocketB in the meanwhile also connect or would it have to wait until SocketA is done /timed out?

like image 777
Toby Avatar asked May 10 '12 09:05

Toby


2 Answers

All the work is done in the thread where io_service.run() runs.

However, the call to any async_ method won't block this specific thread: it behaves exactly like if io_service.run() called select() on several events, and "returns" (calls a callback) whenever such an event is raised. That is, if you call:

socketA->async_connect();
socketB->async_connect();

socketB may as well connect before socketA and the associated callback would then be called first, still in the thread io_service.run() runs.

That's all the beauty of Boost Asio: it takes a very good care about polling, waiting and raising events when it is more appropriate, leaving you with the "easy" part.

like image 50
ereOn Avatar answered Oct 08 '22 18:10

ereOn


You shouldn't try to predict order of execution for asynchronous operations here. async_connect just signals to io_service and returns immediately. The real work gets done in io_service object's event processing loop (io_service::run), but you don't know exact specifics. It most likely uses OS-specific asynchronous IO functions.

It's not clear what you're trying to achieve. Maybe you should use synchronous operations. Maybe you should use thread synchronization functionality. Maybe io_service::run_one will help you (it executes at most one handler).

Maybe you'll want to call io_service::run multiple times in separate threads, creating a thread pool. That way one long completion handler won't block all the others.

boost::asio::io_service service;
const size_t ASIO_THREAD_COUNT = 3;
boost::thread_group threadGroup;
for (size_t i = 0; i < ASIO_THREAD_COUNT; ++i)
        threadGroup.create_thread(boost::bind(&boost::asio::io_service::run,
            &service, boost::system::error_code()));
like image 21
Vsevolod Golovanov Avatar answered Oct 08 '22 17:10

Vsevolod Golovanov