diff options
Diffstat (limited to '3rdparty/asio/src/doc/overview/strands.qbk')
-rw-r--r-- | 3rdparty/asio/src/doc/overview/strands.qbk | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/3rdparty/asio/src/doc/overview/strands.qbk b/3rdparty/asio/src/doc/overview/strands.qbk new file mode 100644 index 00000000000..0b6ff050dc6 --- /dev/null +++ b/3rdparty/asio/src/doc/overview/strands.qbk @@ -0,0 +1,85 @@ +[/ + / Copyright (c) 2003-2016 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] |