asio::async_write(m_socket, asio::buffer(buf, bytes),
custom_alloc(m_strand.wrap(custom_alloc(_OnSend))));
Does this code guarantee
UPD: This answer is wrong=) For anyone interested you can check details in the tail of comments, thanks to Tanner Sansbury.
No. This guarantees your completion handler will be called with strand lock. This not includes calls to async_write_some.
Also boost::asio does not have something like "write queue" and you need to manage async_write calls in order to prevent writing mixed content.
With the following code:
asio::async_write(stream, ..., custom_alloc(m_strand.wrap(...)));
For this composed operation, all calls to stream.async_write_some() will be invoked within m_strand if all of the following conditions are true:
The initiating async_write(...) call is running within m_strand():
assert(m_strand.running_in_this_thread());
asio::async_write(stream, ..., custom_alloc(m_strand.wrap(...)));
The return type from custom_alloc is either:
the exact type returned from strand::wrap()
template <typename Handler>
Handler custom_alloc(Handler) { ... }
a custom handler that appropriate chains invocations of asio_handler_invoke():
template <class Handler>
class custom_handler
{
public:
custom_handler(Handler handler)
: handler_(handler)
{}
template <class... Args>
void operator()(Args&&... args)
{
handler_(std::forward<Args>(args)...);
}
template <typename Function>
friend void asio_handler_invoke(
Function intermediate_handler,
custom_handler* my_handler)
{
// Support chaining custom strategies incase the wrapped handler
// has a custom strategy of its own.
using boost::asio::asio_handler_invoke;
asio_handler_invoke(intermediate_handler, &my_handler->handler_);
}
private:
Handler handler_;
};
template <typename Handler>
custom_handler<Handler> custom_alloc(Handler handler)
{
return {handler};
}
See this answer for more details on strands, and this answer for details on asio_handler_invoke.