2

I have worked with asio library for a few projects and have always managed to get it work, but I feel there are somethings of it that I have not entirely/clearly understood so far. I am wondering how async_receive works.

I googled around a bit and had a look at the implementation but didn't understand it quite well. This is the way that I often use async communication:

socket.async_receive(receive_buffer, receiveHandler);

where receiveHandler is the function that will be called upon the arrival of data on the socket. I know that the async_receive call return immediately. So here are my questions:

  1. Does async_receive create a new thread each time it is called? If not, does it mean that there is a thread responsible to waiting for data and when it arrives, it calls the handler function? When does this thread get created?
  2. If I were to turn this call into a recursive call by using a lambda function like this:
void cyclicReceive() {
  // Imagine the whole thing is in a class, so "this" means something here and
  // "receiveHandler" is still a valid function that gets called.
  socket.async_receive(receive_buffer,
    [this](const asio::error_code& error_code, const std::size_t num_bytes) 
    {
       receiveHandler(error_code, num_bytes);
       cyclicReceive();
    });
}

is there any danger of stack overflow? Why not?

I tried to show a minimal example by removing unnecessary details, so the exact syntax might be a bit wrong.

Keivan
  • 673
  • 7
  • 15

1 Answers1

1
  1. Asio does not create implicitly any new threads. In general it is based on queue of commands. When you call io.run() the framework is taking the commands from the queue and executing them until queue is empty. All the async_ operations in ASIO push new commands to the internal queue.

  2. Therefore there is no risk of stack overflow. Worst possible but not really probable scenario is out_of_memory exception when there is no space left for commands in command queue (which is very unlikely).

bartop
  • 9,971
  • 1
  • 23
  • 54
  • Thank you for the answer. That clarifies much. I guess underneath it still has to call a blocking `recv` then? Would this OOM then happen if one receive stayed blocked and we keep on pushing to the queue? – Keivan Jun 23 '21 at 09:15
  • @Keivan AFAIK `async_receive` uses nonblocking sockets and the `receive` uses blocking one. Of course, if one pushes too much into the queue and `recv`s keeps to be re-scheduled OOM may happen (though I don't thinks it is very likely scenario considering modern ammounts of memory) – bartop Jun 23 '21 at 14:02
  • 1
    Yes true. I got the part about the likelihood of it being quite low. Thanks again. – Keivan Jun 24 '21 at 19:34