H
H
HamsterGamer2021-12-11 23:59:59
ASIO
HamsterGamer, 2021-12-11 23:59:59

How does the simultaneous asynchronous read and write from the boost.asio example work?

I'm trying to parse an example of an asynchronous chat with off. site:
async_client
async_server
chat_message

I seem to have completely understood the client, except for 2 of my questions that torment me a lot, namely:

1) io_service:: run in a separate thread works as a state machine, according to the principle of a queue, where it collects asynchronous calls . So that io_service.run() does not terminate, after connecting, it starts listening on the server socket, waiting for a message, here is the listing (for details, see the async_client code):

void do_read_header()
    {
        boost::asio::async_read(socket_,
                                boost::asio::buffer(read_msg_.data(), chat_message::header_length),
                                [this](boost::system::error_code ec, std::size_t /*length*/)
                                {
                                    if (!ec && read_msg_.decode_header())
                                    {
                                        do_read_body();
                                    }
                                    else
                                    {
                                        socket_.close();
                                    }
                                });
    }

However, in the main function thread, the user starts typing and adds a new task to the io_service, namely the following listing (see the async_client code for details):
void do_write()
    {
        boost::asio::async_write(socket_,
                                 boost::asio::buffer(write_msgs_.front().data(),
                                                     write_msgs_.front().length()),
                                 [this](boost::system::error_code ec, std::size_t /*length*/)
                                 {
                                     if (!ec)
                                     {
                                         write_msgs_.pop_front();
                                         if (!write_msgs_.empty())
                                         {
                                             do_write();
                                         }
                                     }
                                     else
                                     {
                                         socket_.close();
                                     }
                                 });
    }

But why doesn't async_read override async_write? They happen in the same thread (I pledged this), why, by pulling async_read from this queue and waiting for a message, can it simultaneously send messages when the user puts an async_write operation on it?

2) Do operations consume resources during execution like read/async_read/read_some etc.? Or do they work like condition_variable::wait?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
N
nowm, 2021-12-12
@HamsterGamer

async_read doesn't override async_write because it's not exactly what you see in the source codes going on under the hood. Blocks of code like boost::asio::async_read and boost::asio::async_write (which I'll call tasks from now on) are broken down into smaller instructions at compile time. In the background, the system can pause the execution of one task, remembering all its data, switch to another task and execute it for some time, then suspend its execution and switch to the third task, then again to the first, and so on in a circle. Due to this, it is possible to perform several tasks at once within the same thread. This system itself is configured in such a way as to switch these tasks in turn once, for example, in a microsecond. And so she does them in chunks, and you get the impression
Usually asynchrony is organized in this way. If the execution is synchronous, then the system simply works on one task and does not switch anywhere until it completes.
Not sure if I understood your second question correctly. When operations are executed, they naturally consume resources. And if they are not in the execution queue, then no resources are consumed. The system just idly checks the task queue every microsecond.
Read is fired from time to time, so yes, certain resources are consumed because it always checks if there is anything to read, but it checks the buffer for data, not the socket itself. So, resources are consumed, but not as much as when reading existing data.
(Once per microsecond is not an exact value, and I gave it only as an example, so that it is clear that task switching occurs very often.)

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question