115 lines
4.1 KiB
Plaintext
115 lines
4.1 KiB
Plaintext
[/
|
|
/ Copyright (c) 2003-2019 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
|
|
`boost::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).
|
|
|
|
To achieve this, all asynchronous operations obtain the handler's associated
|
|
executor by using the `get_associated_executor` function. For example:
|
|
|
|
boost::asio::associated_executor_t<Handler> a = boost::asio::get_associated_executor(h);
|
|
|
|
The associated executor must satisfy the Executor requirements. It will be used
|
|
by the asynchronous operation to submit both intermediate and final handlers
|
|
for execution.
|
|
|
|
The executor may be customised for a particular handler type by specifying a
|
|
nested type `executor_type` and member function `get_executor()`:
|
|
|
|
class my_handler
|
|
{
|
|
public:
|
|
// Custom implementation of Executor type requirements.
|
|
typedef my_executor executor_type;
|
|
|
|
// Return a custom executor implementation.
|
|
executor_type get_executor() const noexcept
|
|
{
|
|
return my_executor();
|
|
}
|
|
|
|
void operator()() { ... }
|
|
};
|
|
|
|
In more complex cases, the `associated_executor` template may be partially
|
|
specialised directly:
|
|
|
|
struct my_handler
|
|
{
|
|
void operator()() { ... }
|
|
};
|
|
|
|
namespace boost { 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()) noexcept
|
|
{
|
|
return my_executor();
|
|
}
|
|
};
|
|
|
|
} } // namespace boost::asio
|
|
|
|
The `boost::asio::bind_executor()` function is a helper to bind a specific executor
|
|
object, such as a strand, to a completion handler. This binding automatically
|
|
associates an executor as shown above. For example, to bind a strand to a
|
|
completion handler we would simply write:
|
|
|
|
my_socket.async_read_some(my_buffer,
|
|
boost::asio::bind_executor(my_strand,
|
|
[](error_code ec, size_t length)
|
|
{
|
|
// ...
|
|
}));
|
|
|
|
[heading See Also]
|
|
|
|
[link boost_asio.reference.associated_executor associated_executor],
|
|
[link boost_asio.reference.get_associated_executor get_associated_executor],
|
|
[link boost_asio.reference.bind_executor bind_executor],
|
|
[link boost_asio.reference.strand strand],
|
|
[link boost_asio.reference.io_context__strand io_context::strand],
|
|
[link boost_asio.tutorial.tuttimer5 tutorial Timer.5],
|
|
[link boost_asio.examples.cpp03_examples.http_server_3 HTTP server 3 example].
|
|
|
|
[endsect]
|