co_spawn.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. //
  2. // co_spawn.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_CO_SPAWN_HPP
  11. #define BOOST_ASIO_CO_SPAWN_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. #if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
  17. #include <boost/asio/awaitable.hpp>
  18. #include <boost/asio/execution/executor.hpp>
  19. #include <boost/asio/execution_context.hpp>
  20. #include <boost/asio/is_executor.hpp>
  21. #include <boost/asio/detail/push_options.hpp>
  22. namespace boost {
  23. namespace asio {
  24. namespace detail {
  25. template <typename T>
  26. struct awaitable_signature;
  27. template <typename T, typename Executor>
  28. struct awaitable_signature<awaitable<T, Executor>>
  29. {
  30. typedef void type(std::exception_ptr, T);
  31. };
  32. template <typename Executor>
  33. struct awaitable_signature<awaitable<void, Executor>>
  34. {
  35. typedef void type(std::exception_ptr);
  36. };
  37. } // namespace detail
  38. /// Spawn a new coroutined-based thread of execution.
  39. /**
  40. * @param ex The executor that will be used to schedule the new thread of
  41. * execution.
  42. *
  43. * @param a The boost::asio::awaitable object that is the result of calling the
  44. * coroutine's entry point function.
  45. *
  46. * @param token The @ref completion_token that will handle the notification that
  47. * the thread of execution has completed. The function signature of the
  48. * completion handler must be:
  49. * @code void handler(std::exception_ptr, T); @endcode
  50. *
  51. * @par Completion Signature
  52. * @code void(std::exception_ptr, T) @endcode
  53. *
  54. * @par Example
  55. * @code
  56. * boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
  57. * {
  58. * std::size_t bytes_transferred = 0;
  59. *
  60. * try
  61. * {
  62. * char data[1024];
  63. * for (;;)
  64. * {
  65. * std::size_t n = co_await socket.async_read_some(
  66. * boost::asio::buffer(data), boost::asio::use_awaitable);
  67. *
  68. * co_await boost::asio::async_write(socket,
  69. * boost::asio::buffer(data, n), boost::asio::use_awaitable);
  70. *
  71. * bytes_transferred += n;
  72. * }
  73. * }
  74. * catch (const std::exception&)
  75. * {
  76. * }
  77. *
  78. * co_return bytes_transferred;
  79. * }
  80. *
  81. * // ...
  82. *
  83. * boost::asio::co_spawn(my_executor,
  84. * echo(std::move(my_tcp_socket)),
  85. * [](std::exception_ptr e, std::size_t n)
  86. * {
  87. * std::cout << "transferred " << n << "\n";
  88. * });
  89. * @endcode
  90. *
  91. * @par Per-Operation Cancellation
  92. * The new thread of execution is created with a cancellation state that
  93. * supports @c cancellation_type::terminal values only. To change the
  94. * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
  95. */
  96. template <typename Executor, typename T, typename AwaitableExecutor,
  97. BOOST_ASIO_COMPLETION_TOKEN_FOR(
  98. void(std::exception_ptr, T)) CompletionToken
  99. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
  100. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
  101. CompletionToken, void(std::exception_ptr, T))
  102. co_spawn(const Executor& ex, awaitable<T, AwaitableExecutor> a,
  103. CompletionToken&& token
  104. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
  105. constraint_t<
  106. (is_executor<Executor>::value || execution::is_executor<Executor>::value)
  107. && is_convertible<Executor, AwaitableExecutor>::value
  108. > = 0);
  109. /// Spawn a new coroutined-based thread of execution.
  110. /**
  111. * @param ex The executor that will be used to schedule the new thread of
  112. * execution.
  113. *
  114. * @param a The boost::asio::awaitable object that is the result of calling the
  115. * coroutine's entry point function.
  116. *
  117. * @param token The @ref completion_token that will handle the notification that
  118. * the thread of execution has completed. The function signature of the
  119. * completion handler must be:
  120. * @code void handler(std::exception_ptr); @endcode
  121. *
  122. * @par Completion Signature
  123. * @code void(std::exception_ptr) @endcode
  124. *
  125. * @par Example
  126. * @code
  127. * boost::asio::awaitable<void> echo(tcp::socket socket)
  128. * {
  129. * try
  130. * {
  131. * char data[1024];
  132. * for (;;)
  133. * {
  134. * std::size_t n = co_await socket.async_read_some(
  135. * boost::asio::buffer(data), boost::asio::use_awaitable);
  136. *
  137. * co_await boost::asio::async_write(socket,
  138. * boost::asio::buffer(data, n), boost::asio::use_awaitable);
  139. * }
  140. * }
  141. * catch (const std::exception& e)
  142. * {
  143. * std::cerr << "Exception: " << e.what() << "\n";
  144. * }
  145. * }
  146. *
  147. * // ...
  148. *
  149. * boost::asio::co_spawn(my_executor,
  150. * echo(std::move(my_tcp_socket)),
  151. * boost::asio::detached);
  152. * @endcode
  153. *
  154. * @par Per-Operation Cancellation
  155. * The new thread of execution is created with a cancellation state that
  156. * supports @c cancellation_type::terminal values only. To change the
  157. * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
  158. */
  159. template <typename Executor, typename AwaitableExecutor,
  160. BOOST_ASIO_COMPLETION_TOKEN_FOR(
  161. void(std::exception_ptr)) CompletionToken
  162. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
  163. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
  164. CompletionToken, void(std::exception_ptr))
  165. co_spawn(const Executor& ex, awaitable<void, AwaitableExecutor> a,
  166. CompletionToken&& token
  167. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
  168. constraint_t<
  169. (is_executor<Executor>::value || execution::is_executor<Executor>::value)
  170. && is_convertible<Executor, AwaitableExecutor>::value
  171. > = 0);
  172. /// Spawn a new coroutined-based thread of execution.
  173. /**
  174. * @param ctx An execution context that will provide the executor to be used to
  175. * schedule the new thread of execution.
  176. *
  177. * @param a The boost::asio::awaitable object that is the result of calling the
  178. * coroutine's entry point function.
  179. *
  180. * @param token The @ref completion_token that will handle the notification that
  181. * the thread of execution has completed. The function signature of the
  182. * completion handler must be:
  183. * @code void handler(std::exception_ptr); @endcode
  184. *
  185. * @par Completion Signature
  186. * @code void(std::exception_ptr, T) @endcode
  187. *
  188. * @par Example
  189. * @code
  190. * boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
  191. * {
  192. * std::size_t bytes_transferred = 0;
  193. *
  194. * try
  195. * {
  196. * char data[1024];
  197. * for (;;)
  198. * {
  199. * std::size_t n = co_await socket.async_read_some(
  200. * boost::asio::buffer(data), boost::asio::use_awaitable);
  201. *
  202. * co_await boost::asio::async_write(socket,
  203. * boost::asio::buffer(data, n), boost::asio::use_awaitable);
  204. *
  205. * bytes_transferred += n;
  206. * }
  207. * }
  208. * catch (const std::exception&)
  209. * {
  210. * }
  211. *
  212. * co_return bytes_transferred;
  213. * }
  214. *
  215. * // ...
  216. *
  217. * boost::asio::co_spawn(my_io_context,
  218. * echo(std::move(my_tcp_socket)),
  219. * [](std::exception_ptr e, std::size_t n)
  220. * {
  221. * std::cout << "transferred " << n << "\n";
  222. * });
  223. * @endcode
  224. *
  225. * @par Per-Operation Cancellation
  226. * The new thread of execution is created with a cancellation state that
  227. * supports @c cancellation_type::terminal values only. To change the
  228. * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
  229. */
  230. template <typename ExecutionContext, typename T, typename AwaitableExecutor,
  231. BOOST_ASIO_COMPLETION_TOKEN_FOR(
  232. void(std::exception_ptr, T)) CompletionToken
  233. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
  234. typename ExecutionContext::executor_type)>
  235. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
  236. CompletionToken, void(std::exception_ptr, T))
  237. co_spawn(ExecutionContext& ctx, awaitable<T, AwaitableExecutor> a,
  238. CompletionToken&& token
  239. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
  240. typename ExecutionContext::executor_type),
  241. constraint_t<
  242. is_convertible<ExecutionContext&, execution_context&>::value
  243. && is_convertible<typename ExecutionContext::executor_type,
  244. AwaitableExecutor>::value
  245. > = 0);
  246. /// Spawn a new coroutined-based thread of execution.
  247. /**
  248. * @param ctx An execution context that will provide the executor to be used to
  249. * schedule the new thread of execution.
  250. *
  251. * @param a The boost::asio::awaitable object that is the result of calling the
  252. * coroutine's entry point function.
  253. *
  254. * @param token The @ref completion_token that will handle the notification that
  255. * the thread of execution has completed. The function signature of the
  256. * completion handler must be:
  257. * @code void handler(std::exception_ptr); @endcode
  258. *
  259. * @par Completion Signature
  260. * @code void(std::exception_ptr) @endcode
  261. *
  262. * @par Example
  263. * @code
  264. * boost::asio::awaitable<void> echo(tcp::socket socket)
  265. * {
  266. * try
  267. * {
  268. * char data[1024];
  269. * for (;;)
  270. * {
  271. * std::size_t n = co_await socket.async_read_some(
  272. * boost::asio::buffer(data), boost::asio::use_awaitable);
  273. *
  274. * co_await boost::asio::async_write(socket,
  275. * boost::asio::buffer(data, n), boost::asio::use_awaitable);
  276. * }
  277. * }
  278. * catch (const std::exception& e)
  279. * {
  280. * std::cerr << "Exception: " << e.what() << "\n";
  281. * }
  282. * }
  283. *
  284. * // ...
  285. *
  286. * boost::asio::co_spawn(my_io_context,
  287. * echo(std::move(my_tcp_socket)),
  288. * boost::asio::detached);
  289. * @endcode
  290. *
  291. * @par Per-Operation Cancellation
  292. * The new thread of execution is created with a cancellation state that
  293. * supports @c cancellation_type::terminal values only. To change the
  294. * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
  295. */
  296. template <typename ExecutionContext, typename AwaitableExecutor,
  297. BOOST_ASIO_COMPLETION_TOKEN_FOR(
  298. void(std::exception_ptr)) CompletionToken
  299. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
  300. typename ExecutionContext::executor_type)>
  301. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
  302. CompletionToken, void(std::exception_ptr))
  303. co_spawn(ExecutionContext& ctx, awaitable<void, AwaitableExecutor> a,
  304. CompletionToken&& token
  305. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
  306. typename ExecutionContext::executor_type),
  307. constraint_t<
  308. is_convertible<ExecutionContext&, execution_context&>::value
  309. && is_convertible<typename ExecutionContext::executor_type,
  310. AwaitableExecutor>::value
  311. > = 0);
  312. /// Spawn a new coroutined-based thread of execution.
  313. /**
  314. * @param ex The executor that will be used to schedule the new thread of
  315. * execution.
  316. *
  317. * @param f A nullary function object with a return type of the form
  318. * @c boost::asio::awaitable<R,E> that will be used as the coroutine's entry
  319. * point.
  320. *
  321. * @param token The @ref completion_token that will handle the notification
  322. * that the thread of execution has completed. If @c R is @c void, the function
  323. * signature of the completion handler must be:
  324. *
  325. * @code void handler(std::exception_ptr); @endcode
  326. * Otherwise, the function signature of the completion handler must be:
  327. * @code void handler(std::exception_ptr, R); @endcode
  328. *
  329. * @par Completion Signature
  330. * @code void(std::exception_ptr, R) @endcode
  331. * where @c R is the first template argument to the @c awaitable returned by the
  332. * supplied function object @c F:
  333. * @code boost::asio::awaitable<R, AwaitableExecutor> F() @endcode
  334. *
  335. * @par Example
  336. * @code
  337. * boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
  338. * {
  339. * std::size_t bytes_transferred = 0;
  340. *
  341. * try
  342. * {
  343. * char data[1024];
  344. * for (;;)
  345. * {
  346. * std::size_t n = co_await socket.async_read_some(
  347. * boost::asio::buffer(data), boost::asio::use_awaitable);
  348. *
  349. * co_await boost::asio::async_write(socket,
  350. * boost::asio::buffer(data, n), boost::asio::use_awaitable);
  351. *
  352. * bytes_transferred += n;
  353. * }
  354. * }
  355. * catch (const std::exception&)
  356. * {
  357. * }
  358. *
  359. * co_return bytes_transferred;
  360. * }
  361. *
  362. * // ...
  363. *
  364. * boost::asio::co_spawn(my_executor,
  365. * [socket = std::move(my_tcp_socket)]() mutable
  366. * -> boost::asio::awaitable<void>
  367. * {
  368. * try
  369. * {
  370. * char data[1024];
  371. * for (;;)
  372. * {
  373. * std::size_t n = co_await socket.async_read_some(
  374. * boost::asio::buffer(data), boost::asio::use_awaitable);
  375. *
  376. * co_await boost::asio::async_write(socket,
  377. * boost::asio::buffer(data, n), boost::asio::use_awaitable);
  378. * }
  379. * }
  380. * catch (const std::exception& e)
  381. * {
  382. * std::cerr << "Exception: " << e.what() << "\n";
  383. * }
  384. * }, boost::asio::detached);
  385. * @endcode
  386. *
  387. * @par Per-Operation Cancellation
  388. * The new thread of execution is created with a cancellation state that
  389. * supports @c cancellation_type::terminal values only. To change the
  390. * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
  391. */
  392. template <typename Executor, typename F,
  393. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
  394. result_of_t<F()>>::type) CompletionToken
  395. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
  396. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
  397. typename detail::awaitable_signature<result_of_t<F()>>::type)
  398. co_spawn(const Executor& ex, F&& f,
  399. CompletionToken&& token
  400. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
  401. constraint_t<
  402. is_executor<Executor>::value || execution::is_executor<Executor>::value
  403. > = 0);
  404. /// Spawn a new coroutined-based thread of execution.
  405. /**
  406. * @param ctx An execution context that will provide the executor to be used to
  407. * schedule the new thread of execution.
  408. *
  409. * @param f A nullary function object with a return type of the form
  410. * @c boost::asio::awaitable<R,E> that will be used as the coroutine's entry
  411. * point.
  412. *
  413. * @param token The @ref completion_token that will handle the notification
  414. * that the thread of execution has completed. If @c R is @c void, the function
  415. * signature of the completion handler must be:
  416. *
  417. * @code void handler(std::exception_ptr); @endcode
  418. * Otherwise, the function signature of the completion handler must be:
  419. * @code void handler(std::exception_ptr, R); @endcode
  420. *
  421. * @par Completion Signature
  422. * @code void(std::exception_ptr, R) @endcode
  423. * where @c R is the first template argument to the @c awaitable returned by the
  424. * supplied function object @c F:
  425. * @code boost::asio::awaitable<R, AwaitableExecutor> F() @endcode
  426. *
  427. * @par Example
  428. * @code
  429. * boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
  430. * {
  431. * std::size_t bytes_transferred = 0;
  432. *
  433. * try
  434. * {
  435. * char data[1024];
  436. * for (;;)
  437. * {
  438. * std::size_t n = co_await socket.async_read_some(
  439. * boost::asio::buffer(data), boost::asio::use_awaitable);
  440. *
  441. * co_await boost::asio::async_write(socket,
  442. * boost::asio::buffer(data, n), boost::asio::use_awaitable);
  443. *
  444. * bytes_transferred += n;
  445. * }
  446. * }
  447. * catch (const std::exception&)
  448. * {
  449. * }
  450. *
  451. * co_return bytes_transferred;
  452. * }
  453. *
  454. * // ...
  455. *
  456. * boost::asio::co_spawn(my_io_context,
  457. * [socket = std::move(my_tcp_socket)]() mutable
  458. * -> boost::asio::awaitable<void>
  459. * {
  460. * try
  461. * {
  462. * char data[1024];
  463. * for (;;)
  464. * {
  465. * std::size_t n = co_await socket.async_read_some(
  466. * boost::asio::buffer(data), boost::asio::use_awaitable);
  467. *
  468. * co_await boost::asio::async_write(socket,
  469. * boost::asio::buffer(data, n), boost::asio::use_awaitable);
  470. * }
  471. * }
  472. * catch (const std::exception& e)
  473. * {
  474. * std::cerr << "Exception: " << e.what() << "\n";
  475. * }
  476. * }, boost::asio::detached);
  477. * @endcode
  478. *
  479. * @par Per-Operation Cancellation
  480. * The new thread of execution is created with a cancellation state that
  481. * supports @c cancellation_type::terminal values only. To change the
  482. * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
  483. */
  484. template <typename ExecutionContext, typename F,
  485. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
  486. result_of_t<F()>>::type) CompletionToken
  487. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
  488. typename ExecutionContext::executor_type)>
  489. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
  490. typename detail::awaitable_signature<result_of_t<F()>>::type)
  491. co_spawn(ExecutionContext& ctx, F&& f,
  492. CompletionToken&& token
  493. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
  494. typename ExecutionContext::executor_type),
  495. constraint_t<
  496. is_convertible<ExecutionContext&, execution_context&>::value
  497. > = 0);
  498. } // namespace asio
  499. } // namespace boost
  500. #include <boost/asio/detail/pop_options.hpp>
  501. #include <boost/asio/impl/co_spawn.hpp>
  502. #endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
  503. #endif // BOOST_ASIO_CO_SPAWN_HPP