• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1[/
2 / Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
3 /
4 / Distributed under the Boost Software License, Version 1.0. (See accompanying
5 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 /]
7
8[section:strands Strands: Use Threads Without Explicit Locking]
9
10A strand is defined as a strictly sequential invocation of event handlers (i.e.
11no concurrent invocation). Use of strands allows execution of code in a
12multithreaded program without the need for explicit locking (e.g. using
13mutexes).
14
15Strands may be either implicit or explicit, as illustrated by the following
16alternative approaches:
17
18* Calling io_context::run() from only one thread means all event handlers
19  execute in an implicit strand, due to the io_context's guarantee that handlers
20  are only invoked from inside run().
21
22* Where there is a single chain of asynchronous operations associated with a
23  connection (e.g. in a half duplex protocol implementation like HTTP) there is
24  no possibility of concurrent execution of the handlers. This is an implicit
25  strand.
26
27* An explicit strand is an instance of `strand<>` or `io_context::strand`. All
28  event handler function objects need to be bound to the strand using
29  `boost::asio::bind_executor()` or otherwise posted/dispatched through the strand
30  object.
31
32In the case of composed asynchronous operations, such as `async_read()` or
33`async_read_until()`, if a completion handler goes through a strand, then all
34intermediate handlers should also go through the same strand. This is needed to
35ensure thread safe access for any objects that are shared between the caller
36and the composed operation (in the case of `async_read()` it's the socket,
37which the caller can `close()` to cancel the operation).
38
39To achieve this, all asynchronous operations obtain the handler's associated
40executor by using the `get_associated_executor` function. For example:
41
42  boost::asio::associated_executor_t<Handler> a = boost::asio::get_associated_executor(h);
43
44The associated executor must satisfy the Executor requirements. It will be used
45by the asynchronous operation to submit both intermediate and final handlers
46for execution.
47
48The executor may be customised for a particular handler type by specifying a
49nested type `executor_type` and member function `get_executor()`:
50
51  class my_handler
52  {
53  public:
54    // Custom implementation of Executor type requirements.
55    typedef my_executor executor_type;
56
57    // Return a custom executor implementation.
58    executor_type get_executor() const noexcept
59    {
60      return my_executor();
61    }
62
63    void operator()() { ... }
64  };
65
66In more complex cases, the `associated_executor` template may be partially
67specialised directly:
68
69  struct my_handler
70  {
71    void operator()() { ... }
72  };
73
74  namespace boost { namespace asio {
75
76    template <class Executor>
77    struct associated_executor<my_handler, Executor>
78    {
79      // Custom implementation of Executor type requirements.
80      typedef my_executor type;
81
82      // Return a custom executor implementation.
83      static type get(const my_handler&,
84          const Executor& = Executor()) noexcept
85      {
86        return my_executor();
87      }
88    };
89
90  } } // namespace boost::asio
91
92The `boost::asio::bind_executor()` function is a helper to bind a specific executor
93object, such as a strand, to a completion handler. This binding automatically
94associates an executor as shown above. For example, to bind a strand to a
95completion handler we would simply write:
96
97  my_socket.async_read_some(my_buffer,
98      boost::asio::bind_executor(my_strand,
99        [](error_code ec, size_t length)
100        {
101          // ...
102        }));
103
104[heading See Also]
105
106[link boost_asio.reference.associated_executor associated_executor],
107[link boost_asio.reference.get_associated_executor get_associated_executor],
108[link boost_asio.reference.bind_executor bind_executor],
109[link boost_asio.reference.strand strand],
110[link boost_asio.reference.io_context__strand io_context::strand],
111[link boost_asio.tutorial.tuttimer5 tutorial Timer.5],
112[link boost_asio.examples.cpp03_examples.http_server_3 HTTP server 3 example].
113
114[endsect]
115