strand.hpp 17 KB

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