strands.qbk 4.1 KB

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