Sreeraj Chundayil
Sreeraj Chundayil

Reputation: 5859

Why do we need io_service in boost?

I am trying to learn Boost.asio library. Now I can create a client and server which can communicate.

Why do we need to define an io_service object? Because if that is the only type of object available for the sockets to register/communicate with underlying OS, why do we have to define it anyways. Can't the sockets automatically guess it? What am I missing here?

Upvotes: 4

Views: 424

Answers (2)

collier
collier

Reputation: 111

boost::asio::io_service is a central part of any asio related application, serving two roles:

  1. It is a queue of function objects. You could use it even in non-network related software like this:

    void func1() { //do something } void func2(int x) { // do something else using x }

    int main() { boost::asio::io_service io; io.post(func1); io.post(boost::bind(func2, 123)); io.run(); }

This sample of code will execute sequentially the two functions the moment you call io.run() - not during posting. Posting to the io_service is merely an enque operation. You might wonder why this could be usefull. The answer is that in this trivial example obviously it is not. But if you think that method run() for the same io_service instance can be called by two or more threads at the same time then you end up with a model where several threads can act as workers for work items that are produced by other threads. It is a very powerful idea that facilitates multi-threading.

  1. It is a select-loop: In a networking app you might need to handle a large number of file descriptors representing sockets. Traditionaly, this is done in a while loop that more or less looks like that: while (!done) { // check which file descriptors are readable or writable - this is done with poll(), select() etc // for each readable file descriptor: read into some buffer and process received bytes // for each writable file descriptor: write any pending bytes for that descriptor - if any. }

So, every time that you call something like:

boost::asio::async_read(my_asio_socket, my_buffer, boost::bind(my_callback,...))

what will really happen is that the underlying descriptor will be tested through the select() mechanism for readability. When the descriptor becomes readable, data will be stored in my_buffer and when the buffer becomes full the function object constructed through bind(...) will be inserted in the function object queue of the io_service. Hence the thread that is executing my_io_service.run() will wake up and execute this callback.

Please note that multiple threads are not mandatory. You can still work with the main thread as in the first example. It is just that io_service can facilitate dispatching the load to several threads if you design you app that way.

Hope this helps.

Upvotes: 2

sehe
sehe

Reputation: 392954

Are you reverse-discovering why singletons are bad? That's your answer.

As it is done, you are in control and get to decide how many resources are shared between services in Asio.

Because of that, you can now

  • use Asio in your application even though one of the libraries you link to also uses it
  • use Asio with a service per thread (so there will be no shared state) or with many threads per service

etc.

Upvotes: 9

Related Questions