strand.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. //
  2. // strand.hpp
  3. // ~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2024 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/execution/blocking.hpp>
  19. #include <boost/asio/execution/executor.hpp>
  20. #include <boost/asio/is_executor.hpp>
  21. #include <boost/asio/detail/push_options.hpp>
  22. namespace boost {
  23. namespace asio {
  24. /// Provides serialised function invocation for any executor type.
  25. template <typename Executor>
  26. class strand
  27. {
  28. public:
  29. /// The type of the underlying executor.
  30. typedef Executor inner_executor_type;
  31. /// Default constructor.
  32. /**
  33. * This constructor is only valid if the underlying executor type is default
  34. * constructible.
  35. */
  36. strand()
  37. : executor_(),
  38. impl_(strand::create_implementation(executor_))
  39. {
  40. }
  41. /// Construct a strand for the specified executor.
  42. template <typename Executor1>
  43. explicit strand(const Executor1& e,
  44. constraint_t<
  45. conditional_t<
  46. !is_same<Executor1, strand>::value,
  47. is_convertible<Executor1, Executor>,
  48. false_type
  49. >::value
  50. > = 0)
  51. : executor_(e),
  52. impl_(strand::create_implementation(executor_))
  53. {
  54. }
  55. /// Copy constructor.
  56. strand(const strand& other) noexcept
  57. : executor_(other.executor_),
  58. impl_(other.impl_)
  59. {
  60. }
  61. /// Converting constructor.
  62. /**
  63. * This constructor is only valid if the @c OtherExecutor type is convertible
  64. * to @c Executor.
  65. */
  66. template <class OtherExecutor>
  67. strand(
  68. const strand<OtherExecutor>& other) noexcept
  69. : executor_(other.executor_),
  70. impl_(other.impl_)
  71. {
  72. }
  73. /// Assignment operator.
  74. strand& operator=(const strand& other) noexcept
  75. {
  76. executor_ = other.executor_;
  77. impl_ = other.impl_;
  78. return *this;
  79. }
  80. /// Converting assignment operator.
  81. /**
  82. * This assignment operator is only valid if the @c OtherExecutor type is
  83. * convertible to @c Executor.
  84. */
  85. template <class OtherExecutor>
  86. strand& operator=(
  87. const strand<OtherExecutor>& other) noexcept
  88. {
  89. executor_ = other.executor_;
  90. impl_ = other.impl_;
  91. return *this;
  92. }
  93. /// Move constructor.
  94. strand(strand&& other) noexcept
  95. : executor_(static_cast<Executor&&>(other.executor_)),
  96. impl_(static_cast<implementation_type&&>(other.impl_))
  97. {
  98. }
  99. /// Converting move constructor.
  100. /**
  101. * This constructor is only valid if the @c OtherExecutor type is convertible
  102. * to @c Executor.
  103. */
  104. template <class OtherExecutor>
  105. strand(strand<OtherExecutor>&& other) noexcept
  106. : executor_(static_cast<OtherExecutor&&>(other.executor_)),
  107. impl_(static_cast<implementation_type&&>(other.impl_))
  108. {
  109. }
  110. /// Move assignment operator.
  111. strand& operator=(strand&& other) noexcept
  112. {
  113. executor_ = static_cast<Executor&&>(other.executor_);
  114. impl_ = static_cast<implementation_type&&>(other.impl_);
  115. return *this;
  116. }
  117. /// Converting move assignment operator.
  118. /**
  119. * This assignment operator is only valid if the @c OtherExecutor type is
  120. * convertible to @c Executor.
  121. */
  122. template <class OtherExecutor>
  123. strand& operator=(strand<OtherExecutor>&& other) noexcept
  124. {
  125. executor_ = static_cast<OtherExecutor&&>(other.executor_);
  126. impl_ = static_cast<implementation_type&&>(other.impl_);
  127. return *this;
  128. }
  129. /// Destructor.
  130. ~strand() noexcept
  131. {
  132. }
  133. /// Obtain the underlying executor.
  134. inner_executor_type get_inner_executor() const noexcept
  135. {
  136. return executor_;
  137. }
  138. /// Forward a query to the underlying executor.
  139. /**
  140. * Do not call this function directly. It is intended for use with the
  141. * boost::asio::query customisation point.
  142. *
  143. * For example:
  144. * @code boost::asio::strand<my_executor_type> ex = ...;
  145. * if (boost::asio::query(ex, boost::asio::execution::blocking)
  146. * == boost::asio::execution::blocking.never)
  147. * ... @endcode
  148. */
  149. template <typename Property>
  150. constraint_t<
  151. can_query<const Executor&, Property>::value,
  152. conditional_t<
  153. is_convertible<Property, execution::blocking_t>::value,
  154. execution::blocking_t,
  155. query_result_t<const Executor&, Property>
  156. >
  157. > query(const Property& p) const
  158. noexcept(is_nothrow_query<const Executor&, Property>::value)
  159. {
  160. return this->query_helper(
  161. is_convertible<Property, execution::blocking_t>(), p);
  162. }
  163. /// Forward a requirement to the underlying executor.
  164. /**
  165. * Do not call this function directly. It is intended for use with the
  166. * boost::asio::require customisation point.
  167. *
  168. * For example:
  169. * @code boost::asio::strand<my_executor_type> ex1 = ...;
  170. * auto ex2 = boost::asio::require(ex1,
  171. * boost::asio::execution::blocking.never); @endcode
  172. */
  173. template <typename Property>
  174. constraint_t<
  175. can_require<const Executor&, Property>::value
  176. && !is_convertible<Property, execution::blocking_t::always_t>::value,
  177. strand<decay_t<require_result_t<const Executor&, Property>>>
  178. > require(const Property& p) const
  179. noexcept(is_nothrow_require<const Executor&, Property>::value)
  180. {
  181. return strand<decay_t<require_result_t<const Executor&, Property>>>(
  182. boost::asio::require(executor_, p), impl_);
  183. }
  184. /// Forward a preference to the underlying executor.
  185. /**
  186. * Do not call this function directly. It is intended for use with the
  187. * boost::asio::prefer customisation point.
  188. *
  189. * For example:
  190. * @code boost::asio::strand<my_executor_type> ex1 = ...;
  191. * auto ex2 = boost::asio::prefer(ex1,
  192. * boost::asio::execution::blocking.never); @endcode
  193. */
  194. template <typename Property>
  195. constraint_t<
  196. can_prefer<const Executor&, Property>::value
  197. && !is_convertible<Property, execution::blocking_t::always_t>::value,
  198. strand<decay_t<prefer_result_t<const Executor&, Property>>>
  199. > prefer(const Property& p) const
  200. noexcept(is_nothrow_prefer<const Executor&, Property>::value)
  201. {
  202. return strand<decay_t<prefer_result_t<const Executor&, Property>>>(
  203. boost::asio::prefer(executor_, p), impl_);
  204. }
  205. #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  206. /// Obtain the underlying execution context.
  207. execution_context& context() const noexcept
  208. {
  209. return executor_.context();
  210. }
  211. /// Inform the strand that it has some outstanding work to do.
  212. /**
  213. * The strand delegates this call to its underlying executor.
  214. */
  215. void on_work_started() const noexcept
  216. {
  217. executor_.on_work_started();
  218. }
  219. /// Inform the strand that some work is no longer outstanding.
  220. /**
  221. * The strand delegates this call to its underlying executor.
  222. */
  223. void on_work_finished() const noexcept
  224. {
  225. executor_.on_work_finished();
  226. }
  227. #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  228. /// Request the strand to invoke the given function object.
  229. /**
  230. * This function is used to ask the strand to execute the given function
  231. * object on its underlying executor. The function object will be executed
  232. * according to the properties of the underlying executor.
  233. *
  234. * @param f The function object to be called. The executor will make
  235. * a copy of the handler object as required. The function signature of the
  236. * function object must be: @code void function(); @endcode
  237. */
  238. template <typename Function>
  239. constraint_t<
  240. traits::execute_member<const Executor&, Function>::is_valid,
  241. void
  242. > execute(Function&& f) const
  243. {
  244. detail::strand_executor_service::execute(impl_,
  245. executor_, static_cast<Function&&>(f));
  246. }
  247. #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  248. /// Request the strand to invoke the given function object.
  249. /**
  250. * This function is used to ask the strand to execute the given function
  251. * object on its underlying executor. The function object will be executed
  252. * inside this function if the strand is not otherwise busy and if the
  253. * underlying executor's @c dispatch() function is also able to execute the
  254. * function before returning.
  255. *
  256. * @param f The function object to be called. The executor will make
  257. * a copy of the handler object as required. The function signature of the
  258. * function object must be: @code void function(); @endcode
  259. *
  260. * @param a An allocator that may be used by the executor to allocate the
  261. * internal storage needed for function invocation.
  262. */
  263. template <typename Function, typename Allocator>
  264. void dispatch(Function&& f, const Allocator& a) const
  265. {
  266. detail::strand_executor_service::dispatch(impl_,
  267. executor_, static_cast<Function&&>(f), a);
  268. }
  269. /// Request the strand to invoke the given function object.
  270. /**
  271. * This function is used to ask the executor to execute the given function
  272. * object. The function object will never be executed inside this function.
  273. * Instead, it will be scheduled by the underlying executor's defer function.
  274. *
  275. * @param f The function object to be called. The executor will make
  276. * a copy of the handler object as required. The function signature of the
  277. * function object must be: @code void function(); @endcode
  278. *
  279. * @param a An allocator that may be used by the executor to allocate the
  280. * internal storage needed for function invocation.
  281. */
  282. template <typename Function, typename Allocator>
  283. void post(Function&& f, const Allocator& a) const
  284. {
  285. detail::strand_executor_service::post(impl_,
  286. executor_, static_cast<Function&&>(f), a);
  287. }
  288. /// Request the strand to invoke the given function object.
  289. /**
  290. * This function is used to ask the executor to execute the given function
  291. * object. The function object will never be executed inside this function.
  292. * Instead, it will be scheduled by the underlying executor's defer function.
  293. *
  294. * @param f The function object to be called. The executor will make
  295. * a copy of the handler object as required. The function signature of the
  296. * function object must be: @code void function(); @endcode
  297. *
  298. * @param a An allocator that may be used by the executor to allocate the
  299. * internal storage needed for function invocation.
  300. */
  301. template <typename Function, typename Allocator>
  302. void defer(Function&& f, const Allocator& a) const
  303. {
  304. detail::strand_executor_service::defer(impl_,
  305. executor_, static_cast<Function&&>(f), a);
  306. }
  307. #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  308. /// Determine whether the strand is running in the current thread.
  309. /**
  310. * @return @c true if the current thread is executing a function that was
  311. * submitted to the strand using post(), dispatch() or defer(). Otherwise
  312. * returns @c false.
  313. */
  314. bool running_in_this_thread() const noexcept
  315. {
  316. return detail::strand_executor_service::running_in_this_thread(impl_);
  317. }
  318. /// Compare two strands for equality.
  319. /**
  320. * Two strands are equal if they refer to the same ordered, non-concurrent
  321. * state.
  322. */
  323. friend bool operator==(const strand& a, const strand& b) noexcept
  324. {
  325. return a.impl_ == b.impl_;
  326. }
  327. /// Compare two strands for inequality.
  328. /**
  329. * Two strands are equal if they refer to the same ordered, non-concurrent
  330. * state.
  331. */
  332. friend bool operator!=(const strand& a, const strand& b) noexcept
  333. {
  334. return a.impl_ != b.impl_;
  335. }
  336. #if defined(GENERATING_DOCUMENTATION)
  337. private:
  338. #endif // defined(GENERATING_DOCUMENTATION)
  339. typedef detail::strand_executor_service::implementation_type
  340. implementation_type;
  341. template <typename InnerExecutor>
  342. static implementation_type create_implementation(const InnerExecutor& ex,
  343. constraint_t<
  344. can_query<InnerExecutor, execution::context_t>::value
  345. > = 0)
  346. {
  347. return use_service<detail::strand_executor_service>(
  348. boost::asio::query(ex, execution::context)).create_implementation();
  349. }
  350. template <typename InnerExecutor>
  351. static implementation_type create_implementation(const InnerExecutor& ex,
  352. constraint_t<
  353. !can_query<InnerExecutor, execution::context_t>::value
  354. > = 0)
  355. {
  356. return use_service<detail::strand_executor_service>(
  357. ex.context()).create_implementation();
  358. }
  359. strand(const Executor& ex, const implementation_type& impl)
  360. : executor_(ex),
  361. impl_(impl)
  362. {
  363. }
  364. template <typename Property>
  365. query_result_t<const Executor&, Property> query_helper(
  366. false_type, const Property& property) const
  367. {
  368. return boost::asio::query(executor_, property);
  369. }
  370. template <typename Property>
  371. execution::blocking_t query_helper(true_type, const Property& property) const
  372. {
  373. execution::blocking_t result = boost::asio::query(executor_, property);
  374. return result == execution::blocking.always
  375. ? execution::blocking.possibly : result;
  376. }
  377. Executor executor_;
  378. implementation_type impl_;
  379. };
  380. /** @defgroup make_strand boost::asio::make_strand
  381. *
  382. * @brief The boost::asio::make_strand function creates a @ref strand object for
  383. * an executor or execution context.
  384. */
  385. /*@{*/
  386. /// Create a @ref strand object for an executor.
  387. /**
  388. * @param ex An executor.
  389. *
  390. * @returns A strand constructed with the specified executor.
  391. */
  392. template <typename Executor>
  393. inline strand<Executor> make_strand(const Executor& ex,
  394. constraint_t<
  395. is_executor<Executor>::value || execution::is_executor<Executor>::value
  396. > = 0)
  397. {
  398. return strand<Executor>(ex);
  399. }
  400. /// Create a @ref strand object for an execution context.
  401. /**
  402. * @param ctx An execution context, from which an executor will be obtained.
  403. *
  404. * @returns A strand constructed with the execution context's executor, obtained
  405. * by performing <tt>ctx.get_executor()</tt>.
  406. */
  407. template <typename ExecutionContext>
  408. inline strand<typename ExecutionContext::executor_type>
  409. make_strand(ExecutionContext& ctx,
  410. constraint_t<
  411. is_convertible<ExecutionContext&, execution_context&>::value
  412. > = 0)
  413. {
  414. return strand<typename ExecutionContext::executor_type>(ctx.get_executor());
  415. }
  416. /*@}*/
  417. #if !defined(GENERATING_DOCUMENTATION)
  418. namespace traits {
  419. #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
  420. template <typename Executor>
  421. struct equality_comparable<strand<Executor>>
  422. {
  423. static constexpr bool is_valid = true;
  424. static constexpr bool is_noexcept = true;
  425. };
  426. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
  427. #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
  428. template <typename Executor, typename Function>
  429. struct execute_member<strand<Executor>, Function,
  430. enable_if_t<
  431. traits::execute_member<const Executor&, Function>::is_valid
  432. >>
  433. {
  434. static constexpr bool is_valid = true;
  435. static constexpr bool is_noexcept = false;
  436. typedef void result_type;
  437. };
  438. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
  439. #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
  440. template <typename Executor, typename Property>
  441. struct query_member<strand<Executor>, Property,
  442. enable_if_t<
  443. can_query<const Executor&, Property>::value
  444. >>
  445. {
  446. static constexpr bool is_valid = true;
  447. static constexpr bool is_noexcept =
  448. is_nothrow_query<Executor, Property>::value;
  449. typedef conditional_t<
  450. is_convertible<Property, execution::blocking_t>::value,
  451. execution::blocking_t, query_result_t<Executor, Property>> result_type;
  452. };
  453. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
  454. #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
  455. template <typename Executor, typename Property>
  456. struct require_member<strand<Executor>, Property,
  457. enable_if_t<
  458. can_require<const Executor&, Property>::value
  459. && !is_convertible<Property, execution::blocking_t::always_t>::value
  460. >>
  461. {
  462. static constexpr bool is_valid = true;
  463. static constexpr bool is_noexcept =
  464. is_nothrow_require<Executor, Property>::value;
  465. typedef strand<decay_t<require_result_t<Executor, Property>>> result_type;
  466. };
  467. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
  468. #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
  469. template <typename Executor, typename Property>
  470. struct prefer_member<strand<Executor>, Property,
  471. enable_if_t<
  472. can_prefer<const Executor&, Property>::value
  473. && !is_convertible<Property, execution::blocking_t::always_t>::value
  474. >>
  475. {
  476. static constexpr bool is_valid = true;
  477. static constexpr bool is_noexcept =
  478. is_nothrow_prefer<Executor, Property>::value;
  479. typedef strand<decay_t<prefer_result_t<Executor, Property>>> result_type;
  480. };
  481. #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
  482. } // namespace traits
  483. #endif // !defined(GENERATING_DOCUMENTATION)
  484. } // namespace asio
  485. } // namespace boost
  486. #include <boost/asio/detail/pop_options.hpp>
  487. // If both io_context.hpp and strand.hpp have been included, automatically
  488. // include the header file needed for the io_context::strand class.
  489. #if !defined(BOOST_ASIO_NO_EXTENSIONS)
  490. # if defined(BOOST_ASIO_IO_CONTEXT_HPP)
  491. # include <boost/asio/io_context_strand.hpp>
  492. # endif // defined(BOOST_ASIO_IO_CONTEXT_HPP)
  493. #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
  494. #endif // BOOST_ASIO_STRAND_HPP