| [/ |
| / Copyright (c) 2003-2021 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] |