123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- [/
- / 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]
|