Is the order that data is sent to a socket with boost::asio guaranteed at all?
That is, I'm making multiple calls to
boost::asio::async_write(socket, buffer, completionHandler)
and I'm seeing some odd behaviour where the client isn't apparently receiving the data I think I'm sending, so I'm wanting to make sure that this is doing what I hope it's doing. Note that I'm not waiting for the completion handler to be called between each write, I'm just firing a bunch of async_write calls and naively expecting the data to be written to the socket in the same order.
The strand documentation in asio says:
Where there is a single chain of asynchronous operations associated with a connection (e.g. in a half duplex protocol implementation like HTTP) there is no possibility of concurrent execution of the handlers. This is an implicit strand.
I take this to mean that using a strand won't change anything, as the socket provides an implicit strand.
The strand documentation in general talks about strictly sequential invocation of event handlers. However it's not clear to me whether the data written to the connection will be written in the order in which I make calls to async_write.
Is the order that data is written to the socket guaranteed?
Making a call to async_write while another one is in progress is not allowed. This is true regardless of whether you are using one thread or multiple threads. From the asio docs:
This operation is implemented in terms of zero or more calls to the stream's async_write_some function, and is known as a composed operation. The program must ensure that the stream performs no other write operations (such as async_write, the stream's async_write_some function, or any other composed operations that perform writes) until this operation completes.
Edit: The workaround for this is to maintain a buffer of bytes to write, and add to that instead of calling async_write when a write is already in progress. When the current write completes, call async_write again with that buffer.
Edit 2: The answer to this question has an example of how do this. It uses strands so would work in a multi-threaded application (but is a bit more complex than is necessary if your application is single threaded).
Edit 3: One final clarification. Using a strand wouldn't help because a strand guarantees that your code (for that strand) is only running in one thread at once, but doesn't guarantee that only one operation is happening at once. In other words, if you call async_write in a handler, then as soon as that handler returns more stuff can be called in that strand, even if the async_write is still in progress. You need to manually store some state indicating that you've started an async_write and (here is the key part) update that state in the completion handler that you passed as a parameter to async_write.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With