strand.hpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. //
  2. // strand.hpp
  3. // ~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 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)),
  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);
  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=(
  116. const strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT
  117. {
  118. executor_ = BOOST_ASIO_MOVE_CAST(OtherExecutor)(other);
  119. impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_);
  120. return *this;
  121. }
  122. #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
  123. /// Destructor.
  124. ~strand()
  125. {
  126. }
  127. /// Obtain the underlying executor.
  128. inner_executor_type get_inner_executor() const BOOST_ASIO_NOEXCEPT
  129. {
  130. return executor_;
  131. }
  132. /// Obtain the underlying execution context.
  133. execution_context& context() const BOOST_ASIO_NOEXCEPT
  134. {
  135. return executor_.context();
  136. }
  137. /// Inform the strand that it has some outstanding work to do.
  138. /**
  139. * The strand delegates this call to its underlying executor.
  140. */
  141. void on_work_started() const BOOST_ASIO_NOEXCEPT
  142. {
  143. executor_.on_work_started();
  144. }
  145. /// Inform the strand that some work is no longer outstanding.
  146. /**
  147. * The strand delegates this call to its underlying executor.
  148. */
  149. void on_work_finished() const BOOST_ASIO_NOEXCEPT
  150. {
  151. executor_.on_work_finished();
  152. }
  153. /// Request the strand to invoke the given function object.
  154. /**
  155. * This function is used to ask the strand to execute the given function
  156. * object on its underlying executor. The function object will be executed
  157. * inside this function if the strand is not otherwise busy and if the
  158. * underlying executor's @c dispatch() function is also able to execute the
  159. * function before returning.
  160. *
  161. * @param f The function object to be called. The executor will make
  162. * a copy of the handler object as required. The function signature of the
  163. * function object must be: @code void function(); @endcode
  164. *
  165. * @param a An allocator that may be used by the executor to allocate the
  166. * internal storage needed for function invocation.
  167. */
  168. template <typename Function, typename Allocator>
  169. void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
  170. {
  171. detail::strand_executor_service::dispatch(impl_,
  172. executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
  173. }
  174. /// Request the strand to invoke the given function object.
  175. /**
  176. * This function is used to ask the executor to execute the given function
  177. * object. The function object will never be executed inside this function.
  178. * Instead, it will be scheduled by the underlying executor's defer function.
  179. *
  180. * @param f The function object to be called. The executor will make
  181. * a copy of the handler object as required. The function signature of the
  182. * function object must be: @code void function(); @endcode
  183. *
  184. * @param a An allocator that may be used by the executor to allocate the
  185. * internal storage needed for function invocation.
  186. */
  187. template <typename Function, typename Allocator>
  188. void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
  189. {
  190. detail::strand_executor_service::post(impl_,
  191. executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
  192. }
  193. /// Request the strand to invoke the given function object.
  194. /**
  195. * This function is used to ask the executor to execute the given function
  196. * object. The function object will never be executed inside this function.
  197. * Instead, it will be scheduled by the underlying executor's defer function.
  198. *
  199. * @param f The function object to be called. The executor will make
  200. * a copy of the handler object as required. The function signature of the
  201. * function object must be: @code void function(); @endcode
  202. *
  203. * @param a An allocator that may be used by the executor to allocate the
  204. * internal storage needed for function invocation.
  205. */
  206. template <typename Function, typename Allocator>
  207. void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const
  208. {
  209. detail::strand_executor_service::defer(impl_,
  210. executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a);
  211. }
  212. /// Determine whether the strand is running in the current thread.
  213. /**
  214. * @return @c true if the current thread is executing a function that was
  215. * submitted to the strand using post(), dispatch() or defer(). Otherwise
  216. * returns @c false.
  217. */
  218. bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT
  219. {
  220. return detail::strand_executor_service::running_in_this_thread(impl_);
  221. }
  222. /// Compare two strands for equality.
  223. /**
  224. * Two strands are equal if they refer to the same ordered, non-concurrent
  225. * state.
  226. */
  227. friend bool operator==(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT
  228. {
  229. return a.impl_ == b.impl_;
  230. }
  231. /// Compare two strands for inequality.
  232. /**
  233. * Two strands are equal if they refer to the same ordered, non-concurrent
  234. * state.
  235. */
  236. friend bool operator!=(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT
  237. {
  238. return a.impl_ != b.impl_;
  239. }
  240. private:
  241. Executor executor_;
  242. typedef detail::strand_executor_service::implementation_type
  243. implementation_type;
  244. implementation_type impl_;
  245. };
  246. /** @defgroup make_strand boost::asio::make_strand
  247. *
  248. * @brief The boost::asio::make_strand function creates a @ref strand object for
  249. * an executor or execution context.
  250. */
  251. /*@{*/
  252. /// Create a @ref strand object for an executor.
  253. template <typename Executor>
  254. inline strand<Executor> make_strand(const Executor& ex,
  255. typename enable_if<is_executor<Executor>::value>::type* = 0)
  256. {
  257. return strand<Executor>(ex);
  258. }
  259. /// Create a @ref strand object for an execution context.
  260. template <typename ExecutionContext>
  261. inline strand<typename ExecutionContext::executor_type>
  262. make_strand(ExecutionContext& ctx,
  263. typename enable_if<
  264. is_convertible<ExecutionContext&, execution_context&>::value>::type* = 0)
  265. {
  266. return strand<typename ExecutionContext::executor_type>(ctx.get_executor());
  267. }
  268. /*@}*/
  269. } // namespace asio
  270. } // namespace boost
  271. #include <boost/asio/detail/pop_options.hpp>
  272. // If both io_context.hpp and strand.hpp have been included, automatically
  273. // include the header file needed for the io_context::strand class.
  274. #if !defined(BOOST_ASIO_NO_EXTENSIONS)
  275. # if defined(BOOST_ASIO_IO_CONTEXT_HPP)
  276. # include <boost/asio/io_context_strand.hpp>
  277. # endif // defined(BOOST_ASIO_IO_CONTEXT_HPP)
  278. #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
  279. #endif // BOOST_ASIO_STRAND_HPP