blob: 0d4a08bff2fb60e94f6b75fc3f2a1ec2499a714f [file] [log] [blame]
[/
/ Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section:strands Strands: Use Threads Without Explicit Locking]
A strand is defined as a strictly sequential invocation of event handlers (i.e.
no concurrent invocation). Use of strands allows execution of code in a
multithreaded program without the need for explicit locking (e.g. using
mutexes).
Strands may be either implicit or explicit, as illustrated by the following
alternative approaches:
* Calling io_context::run() from only one thread means all event handlers
execute in an implicit strand, due to the io_context's guarantee that handlers
are only invoked from inside run().
* 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.
* An explicit strand is an instance of `strand<>` or `io_context::strand`. All
event handler function objects need to be bound to the strand using
`asio::bind_executor()` or otherwise posted/dispatched through the strand
object.
In the case of composed asynchronous operations, such as `async_read()` or
`async_read_until()`, if a completion handler goes through a strand, then all
intermediate handlers should also go through the same strand. This is needed to
ensure thread safe access for any objects that are shared between the caller
and the composed operation (in the case of `async_read()` it's the socket,
which the caller can `close()` to cancel the operation).
This is done by partially specialising the `asio::ssociated_executor<>` trait
for all intermediate handlers. This trait forwards to the corresponding trait
specialisation for the final handler:
struct my_handler
{
void operator()() { ... }
};
namespace asio {
template <class Executor>
struct associated_executor<my_handler, Executor>
{
// Custom implementation of Executor type requirements.
typedef my_executor type;
// Return a custom executor implementation.
static type get(const my_handler&, const Executor& = Executor())
{
return my_executor();
}
};
} // namespace asio
The `asio::bind_executor()` function is a helper to bind a specific executor
object, such as a strand, to a completion handler. This binding automatically
specialises the `associated_executor` trait as shown above. For example, to
bind a strand to a completion handler we would simply write:
my_socket.async_read_some(my_buffer,
asio::bind_executor(my_strand,
[](error_code ec, size_t length)
{
// ...
}));
[heading See Also]
[link asio.reference.bind_executor bind_executor],
[link asio.reference.strand strand],
[link asio.reference.io_context__strand io_context::strand],
[link asio.tutorial.tuttimer5 tutorial Timer.5],
[link asio.examples.cpp03_examples.http_server_3 HTTP server 3 example].
[endsect]