strand.hpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. //
  2. // strand.hpp
  3. // ~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_STRAND_HPP
  11. #define BOOST_ASIO_STRAND_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #include <boost/asio/detail/strand_executor_service.hpp>
  17. #include <boost/asio/detail/type_traits.hpp>
  18. #include <boost/asio/detail/push_options.hpp>
  19. namespace boost {
  20. namespace asio {
  21. /// Provides serialised function invocation for any executor type.
  22. template <typename Executor>
  23. class strand
  24. {
  25. public:
  26. /// The type of the underlying executor.
  27. typedef Executor inner_executor_type;
  28. /// Default constructor.
  29. /**
  30. * This constructor is only valid if the underlying executor type is default
  31. * constructible.
  32. */
  33. strand()
  34. : executor_(),
  35. impl_(use_service<detail::strand_executor_service>(
  36. executor_.context()).create_implementation())
  37. {
  38. }
  39. /// Construct a strand for the specified executor.
  40. explicit strand(const Executor& e)
  41. : executor_(e),
  42. impl_(use_service<detail::strand_executor_service>(
  43. executor_.context()).create_implementation())
  44. {
  45. }
  46. /// Copy constructor.
  47. strand(const strand& other) BOOST_ASIO_NOEXCEPT
  48. : executor_(other.executor_),
  49. impl_(other.impl_)
  50. {
  51. }
  52. /// Converting constructor.
  53. /**
  54. * This constructor is only valid if the @c OtherExecutor type is convertible
  55. * to @c Executor.
  56. */
  57. template <class OtherExecutor>
  58. strand(
  59. const strand<OtherExecutor>& other) BOOST_ASIO_NOEXCEPT
  60. : executor_(other.executor_),
  61. impl_(other.impl_)
  62. {
  63. }
  64. /// Assignment operator.
  65. strand& operator=(const strand& other) BOOST_ASIO_NOEXCEPT
  66. {
  67. executor_ = other.executor_;
  68. impl_ = other.impl_;
  69. return *this;
  70. }
  71. /// Converting assignment operator.
  72. /**
  73. * This assignment operator is only valid if the @c OtherExecutor type is
  74. * convertible to @c Executor.
  75. */
  76. template <class OtherExecutor>
  77. strand& operator=(
  78. const strand<OtherExecutor>& other) BOOST_ASIO_NOEXCEPT
  79. {
  80. executor_ = other.executor_;
  81. impl_ = other.impl_;
  82. return *this;
  83. }
  84. #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
  85. /// Move constructor.
  86. strand(strand&& other) BOOST_ASIO_NOEXCEPT
  87. : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)),
  88. impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_))
  89. {
  90. }
  91. /// Converting move constructor.
  92. /**
  93. * This constructor is only valid if the @c OtherExecutor type is convertible
  94. * to @c Executor.
  95. */
  96. template <class OtherExecutor>
  97. strand(strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT
  98. : executor_(BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.executor_)),
  99. impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_))
  100. {
  101. }
  102. /// Move assignment operator.
  103. strand& operator=(strand&& other) BOOST_ASIO_NOEXCEPT
  104. {
  105. executor_ = BOOST_ASIO_MOVE_CAST(Executor)(other.executor_);
  106. impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_);
  107. return *this;
  108. }
  109. /// Converting move assignment operator.
  110. /**
  111. * This assignment operator is only valid if the @c OtherExecutor type is
  112. * convertible to @c Executor.
  113. */
  114. template <class OtherExecutor>
  115. strand& operator=(strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT
  116. {
  117. executor_ = BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.executor_);
  118. impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_);
  119. return *this;
  120. }
  121. #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
  122. /// Destructor.
  123. ~strand()
  124. {
  125. }
  126. /// Obtain the underlying executor.
  127. inner_executor_type get_inner_executor() const BOOST_ASIO_NOEXCEPT
  128. {
  129. return executor_;
  130. }
  131. /// Obtain the underlying execution context.
  132. execution_context& context() const BOOST_ASIO_NOEXCEPT
  133. {
  134. return executor_.context();
  135. }
  136. /// Inform the strand that it has some outstanding work to do.
  137. /**
  138. * The strand delegates this call to its underlying executor.
  139. */
  140. void on_work_started() const BOOST_ASIO_NOEXCEPT
  141. {
  142. executor_.on_work_started();
  143. }
  144. /// Inform the strand that some work is no longer outstanding.
  145. /**
  146. * The strand delegates this call to its underlying executor.
  147. */
  148. void on_work_finished() const BOOST_ASIO_NOEXCEPT
  149. {
  150. executor_.on_work_finished();
  151. }
  152. /// Request the strand to invoke the given function object.
  153. /**
  154. * This function is used to ask the strand to execute the given function
  155. * object on its underlying executor. The function object will be executed
  156. * inside this function if the strand is not otherwise busy and if the
  157. * underlying executor's @c dispatch() function is also able to execute the
  158. * function before returning.
  159. *
  160. * @param f The function object to be called. The executor will make
  161. * a copy of the handler object as required. The function signature of the
  162. * function object must be: @code void function(); @endcode
  163. *
  164. * @param a An allocator that may be used by the executor to allocate the
  165. * internal storage needed for function invocation.
  166. */
  167. template <typename Function, typename Allocator>
  168. void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
  169. {
  170. detail::strand_executor_service::dispatch(impl_,
  171. executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
  172. }
  173. /// Request the strand to invoke the given function object.
  174. /**
  175. * This function is used to ask the executor to execute the given function
  176. * object. The function object will never be executed inside this function.
  177. * Instead, it will be scheduled by the underlying executor's defer function.
  178. *
  179. * @param f The function object to be called. The executor will make
  180. * a copy of the handler object as required. The function signature of the
  181. * function object must be: @code void function(); @endcode
  182. *
  183. * @param a An allocator that may be used by the executor to allocate the
  184. * internal storage needed for function invocation.
  185. */
  186. template <typename Function, typename Allocator>
  187. void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
  188. {
  189. detail::strand_executor_service::post(impl_,
  190. executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
  191. }
  192. /// Request the strand to invoke the given function object.
  193. /**
  194. * This function is used to ask the executor to execute the given function
  195. * object. The function object will never be executed inside this function.
  196. * Instead, it will be scheduled by the underlying executor's defer function.
  197. *
  198. * @param f The function object to be called. The executor will make
  199. * a copy of the handler object as required. The function signature of the
  200. * function object must be: @code void function(); @endcode
  201. *
  202. * @param a An allocator that may be used by the executor to allocate the
  203. * internal storage needed for function invocation.
  204. */
  205. template <typename Function, typename Allocator>
  206. void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
  207. {
  208. detail::strand_executor_service::defer(impl_,
  209. executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
  210. }
  211. /// Determine whether the strand is running in the current thread.
  212. /**
  213. * @return @c true if the current thread is executing a function that was
  214. * submitted to the strand using post(), dispatch() or defer(). Otherwise
  215. * returns @c false.
  216. */
  217. bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT
  218. {
  219. return detail::strand_executor_service::running_in_this_thread(impl_);
  220. }
  221. /// Compare two strands for equality.
  222. /**
  223. * Two strands are equal if they refer to the same ordered, non-concurrent
  224. * state.
  225. */
  226. friend bool operator==(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT
  227. {
  228. return a.impl_ == b.impl_;
  229. }
  230. /// Compare two strands for inequality.
  231. /**
  232. * Two strands are equal if they refer to the same ordered, non-concurrent
  233. * state.
  234. */
  235. friend bool operator!=(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT
  236. {
  237. return a.impl_ != b.impl_;
  238. }
  239. #if defined(GENERATING_DOCUMENTATION)
  240. private:
  241. #endif // defined(GENERATING_DOCUMENTATION)
  242. Executor executor_;
  243. typedef detail::strand_executor_service::implementation_type
  244. implementation_type;
  245. implementation_type impl_;
  246. };
  247. /** @defgroup make_strand boost::asio::make_strand
  248. *
  249. * @brief The boost::asio::make_strand function creates a @ref strand object for
  250. * an executor or execution context.
  251. */
  252. /*@{*/
  253. /// Create a @ref strand object for an executor.
  254. template <typename Executor>
  255. inline strand<Executor> make_strand(const Executor& ex,
  256. typename enable_if<is_executor<Executor>::value>::type* = 0)
  257. {
  258. return strand<Executor>(ex);
  259. }
  260. /// Create a @ref strand object for an execution context.
  261. template <typename ExecutionContext>
  262. inline strand<typename ExecutionContext::executor_type>
  263. make_strand(ExecutionContext& ctx,
  264. typename enable_if<
  265. is_convertible<ExecutionContext&, execution_context&>::value>::type* = 0)
  266. {
  267. return strand<typename ExecutionContext::executor_type>(ctx.get_executor());
  268. }
  269. /*@}*/
  270. } // namespace asio
  271. } // namespace boost
  272. #include <boost/asio/detail/pop_options.hpp>
  273. // If both io_context.hpp and strand.hpp have been included, automatically
  274. // include the header file needed for the io_context::strand class.
  275. #if !defined(BOOST_ASIO_NO_EXTENSIONS)
  276. # if defined(BOOST_ASIO_IO_CONTEXT_HPP)
  277. # include <boost/asio/io_context_strand.hpp>
  278. # endif // defined(BOOST_ASIO_IO_CONTEXT_HPP)
  279. #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
  280. #endif // BOOST_ASIO_STRAND_HPP