parallel_group.hpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. //
  2. // experimental/parallel_group.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2022 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_EXPERIMENTAL_PARALLEL_GROUP_HPP
  11. #define ASIO_EXPERIMENTAL_PARALLEL_GROUP_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 <utility>
  17. #include "asio/detail/array.hpp"
  18. #include "asio/experimental/cancellation_condition.hpp"
  19. #include "asio/detail/push_options.hpp"
  20. namespace asio {
  21. namespace experimental {
  22. namespace detail {
  23. // Helper trait for getting the completion signature from an async operation.
  24. struct parallel_op_signature_probe {};
  25. template <typename T>
  26. struct parallel_op_signature_probe_result
  27. {
  28. typedef T type;
  29. };
  30. template <typename Op>
  31. struct parallel_op_signature
  32. {
  33. typedef typename decltype(declval<Op>()(
  34. declval<parallel_op_signature_probe>()))::type type;
  35. };
  36. // Helper trait for getting a tuple from a completion signature.
  37. template <typename Signature>
  38. struct parallel_op_signature_as_tuple;
  39. template <typename R, typename... Args>
  40. struct parallel_op_signature_as_tuple<R(Args...)>
  41. {
  42. typedef std::tuple<typename decay<Args>::type...> type;
  43. };
  44. // Helper trait for concatenating completion signatures.
  45. template <std::size_t N, typename Offsets, typename... Signatures>
  46. struct parallel_group_signature;
  47. template <std::size_t N, typename R0, typename... Args0>
  48. struct parallel_group_signature<N, R0(Args0...)>
  49. {
  50. typedef asio::detail::array<std::size_t, N> order_type;
  51. typedef R0 raw_type(Args0...);
  52. typedef R0 type(order_type, Args0...);
  53. };
  54. template <std::size_t N,
  55. typename R0, typename... Args0,
  56. typename R1, typename... Args1>
  57. struct parallel_group_signature<N, R0(Args0...), R1(Args1...)>
  58. {
  59. typedef asio::detail::array<std::size_t, N> order_type;
  60. typedef R0 raw_type(Args0..., Args1...);
  61. typedef R0 type(order_type, Args0..., Args1...);
  62. };
  63. template <std::size_t N, typename Sig0,
  64. typename Sig1, typename... SigN>
  65. struct parallel_group_signature<N, Sig0, Sig1, SigN...>
  66. {
  67. typedef asio::detail::array<std::size_t, N> order_type;
  68. typedef typename parallel_group_signature<N,
  69. typename parallel_group_signature<N, Sig0, Sig1>::raw_type,
  70. SigN...>::raw_type raw_type;
  71. typedef typename parallel_group_signature<N,
  72. typename parallel_group_signature<N, Sig0, Sig1>::raw_type,
  73. SigN...>::type type;
  74. };
  75. template <typename Condition, typename Handler,
  76. typename... Ops, std::size_t... I>
  77. void parallel_group_launch(Condition cancellation_condition, Handler handler,
  78. std::tuple<Ops...>& ops, std::index_sequence<I...>);
  79. } // namespace detail
  80. /// A group of asynchronous operations that may be launched in parallel.
  81. /**
  82. * See the documentation for asio::experimental::make_parallel_group for
  83. * a usage example.
  84. */
  85. template <typename... Ops>
  86. class parallel_group
  87. {
  88. public:
  89. /// Constructor.
  90. explicit parallel_group(Ops... ops)
  91. : ops_(std::move(ops)...)
  92. {
  93. }
  94. /// The completion signature for the group of operations.
  95. typedef typename detail::parallel_group_signature<sizeof...(Ops),
  96. typename detail::parallel_op_signature<Ops>::type...>::type signature;
  97. /// Initiate an asynchronous wait for the group of operations.
  98. /**
  99. * Launches the group and asynchronously waits for completion.
  100. *
  101. * @param cancellation_condition A function object, called on completion of
  102. * an operation within the group, that is used to determine whether to cancel
  103. * the remaining operations. The function object is passed the arguments of
  104. * the completed operation's handler. To trigger cancellation of the remaining
  105. * operations, it must return a asio::cancellation_type value other
  106. * than <tt>asio::cancellation_type::none</tt>.
  107. *
  108. * @param token A completion token whose signature is comprised of
  109. * a @c std::array<std::size_t, N> indicating the completion order of the
  110. * operations, followed by all operations' completion handler arguments.
  111. *
  112. * The library provides the following @c cancellation_condition types:
  113. *
  114. * @li asio::experimental::wait_for_all
  115. * @li asio::experimental::wait_for_one
  116. * @li asio::experimental::wait_for_one_error
  117. * @li asio::experimental::wait_for_one_success
  118. */
  119. template <typename CancellationCondition,
  120. ASIO_COMPLETION_TOKEN_FOR(signature) CompletionToken>
  121. auto async_wait(CancellationCondition cancellation_condition,
  122. CompletionToken&& token)
  123. {
  124. return asio::async_initiate<CompletionToken, signature>(
  125. initiate_async_wait(), token,
  126. std::move(cancellation_condition), std::move(ops_));
  127. }
  128. private:
  129. struct initiate_async_wait
  130. {
  131. template <typename Handler, typename Condition>
  132. void operator()(Handler&& h, Condition&& c, std::tuple<Ops...>&& ops) const
  133. {
  134. detail::parallel_group_launch(std::move(c), std::move(h),
  135. ops, std::make_index_sequence<sizeof...(Ops)>());
  136. }
  137. };
  138. std::tuple<Ops...> ops_;
  139. };
  140. /// Create a group of operations that may be launched in parallel.
  141. /**
  142. * For example:
  143. * @code asio::experimental::make_parallel_group(
  144. * [&](auto token)
  145. * {
  146. * return in.async_read_some(asio::buffer(data), token);
  147. * },
  148. * [&](auto token)
  149. * {
  150. * return timer.async_wait(token);
  151. * }
  152. * ).async_wait(
  153. * asio::experimental::wait_for_all(),
  154. * [](
  155. * std::array<std::size_t, 2> completion_order,
  156. * std::error_code ec1, std::size_t n1,
  157. * std::error_code ec2
  158. * )
  159. * {
  160. * switch (completion_order[0])
  161. * {
  162. * case 0:
  163. * {
  164. * std::cout << "descriptor finished: " << ec1 << ", " << n1 << "\n";
  165. * }
  166. * break;
  167. * case 1:
  168. * {
  169. * std::cout << "timer finished: " << ec2 << "\n";
  170. * }
  171. * break;
  172. * }
  173. * }
  174. * );
  175. * @endcode
  176. */
  177. template <typename... Ops>
  178. ASIO_NODISCARD inline parallel_group<Ops...>
  179. make_parallel_group(Ops... ops)
  180. {
  181. return parallel_group<Ops...>(std::move(ops)...);
  182. }
  183. } // namespace experimental
  184. } // namespace asio
  185. #include "asio/detail/pop_options.hpp"
  186. #include "asio/experimental/impl/parallel_group.hpp"
  187. #endif // ASIO_EXPERIMENTAL_PARALLEL_GROUP_HPP