With concurrent callers the first problem can be resolved easily with a mutex or a strand, using the former if you don't want to buffer the work and the latter if you do. This protects the socket during the function invocations but does nothing for the other problems.
The second problem seems hardest, because it's difficult to see what's going on inside of the code executing asynchronously from the two functions. The async functions both post work to the io_service of the socket.
- The third problem is easilycan be resolved by using a (different) mutex that is locked before the async_write, passed into the completion handler and unlocked at that point. This will prevent any caller from beginning a write until all parts of the preceding write are complete.
Assuming that the work posted to the io_service does not incorporate socket operations, there is no need to limit the io_service to a single thread. It does however reinforce the importance of guarding against concurrent execution of the async functions. So, for example, if one follows the chat example but instead adds another thread to the io_service, there becomes a problem. With async function invocations executing within function handlers, you have concurrent function execution. This would require either a mutex, or all async function invocations to be reposted for execution on a strand (which is just wasteful if resource protection is the objective).
This means any guard around the async_write call (mutex or strand) will not protect the socket if there are multiple io_service threads and more than 64kb of data to post (by default, this may possibly vary). Therefore, in this case, the interleave guard is necessary not only for interleave safety, but also thread safety of the socket. I verified all of this in a debugger.
THE MUTEX OPTION
The async_read and async_write functions internally use the io_service in order to obtain threads on which to post completion handlers, blocking until threads are available. This makes them hazardous to guard with mutex locks. When a mutex is used to guard these functions a deadlock will occur when threads back up against the lock, starving the io_service.