基于C++ Coroutines提案 ‘Stackless Resumable Functions’编写的协程库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_async_modern_cb.cpp 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. 
  2. #include "librf.h"
  3. #include <chrono>
  4. #include <iostream>
  5. #include <string>
  6. #include <thread>
  7. #include <future>
  8. template<typename _Input_t, typename _Callable_t>
  9. __declspec(noinline)
  10. void tostring_async_originalism(_Input_t&& value, _Callable_t&& callback)
  11. {
  12. std::thread([callback = std::move(callback), value = std::forward<_Input_t>(value)]
  13. {
  14. callback(std::to_string(value));
  15. }).detach();
  16. }
  17. //回调适配器的模板类
  18. //这个默认类以_Callable_t作为真正的回调
  19. //返回无意义的int,以便于编译通过
  20. template<typename _Callable_t, typename _Result_t>
  21. struct modern_callback_adapter_t
  22. {
  23. using return_type = int;
  24. using callback_type = _Callable_t;
  25. static std::tuple<callback_type, return_type> traits(_Callable_t&& callback)
  26. {
  27. return { std::forward<_Callable_t>(callback), 0 };
  28. }
  29. };
  30. #define MODERN_CALLBACK_TRAITS(type) \
  31. using _Result_t = type; \
  32. using _Adapter_t = modern_callback_adapter_t<std::decay_t<_Callable_t>, _Result_t>; \
  33. auto adapter = typename _Adapter_t::traits(std::forward<_Callable_t>(callback))
  34. #define MODERN_CALLBACK_CALL() callback = std::move(std::get<0>(adapter))
  35. #define MODERN_CALLBACK_RETURN() return std::move(std::get<1>(adapter))
  36. template<typename _Input_t, typename _Callable_t>
  37. auto tostring_async_macro(_Input_t&& value, _Callable_t&& callback)
  38. {
  39. MODERN_CALLBACK_TRAITS(std::string);
  40. std::thread([MODERN_CALLBACK_CALL(), value = std::forward<_Input_t>(value)]
  41. {
  42. callback(std::to_string(value));
  43. }).detach();
  44. MODERN_CALLBACK_RETURN();
  45. }
  46. //演示如何通过回调适配器模型,将异步回调,扩展到支持future模式,调用链模式,以及协程。
  47. //
  48. //一个使用回调处理结果的异步函数,会涉及五个概念:
  49. //_Input_t:异步函数的输入参数;
  50. //_Callable_t:回调函数,这个回调,必须调用一次,且只能调用一次;
  51. //_Return_t:异步函数的返回值;
  52. //_Result_t:异步函数完成后的结果值,作为回调函数的入参部分;这个参数可以有零至多个;
  53. //_Exception_t:回调函数的异常, 如果不喜欢异常的则忽略这个部分,但就得异步代码将异常处置妥当;
  54. //
  55. //在回调适配器模型里,_Input_t/_Result_t/_Exception_t(可选)是异步函数提供的功能所固有的部分;_Callable_t/_Return_t
  56. //部分并不直接使用,而是通过适配器去另外处理。这样给予适配器一次扩展到future模式,调用链模式的机会,以及支持协程的机会。
  57. //
  58. //tostring_async 演示了在其他线程里,将_Input_t的输入值,转化为std::string类型的_Result_t。
  59. //然后调用void(std::string &&)类型的_Callable_t。忽视异常处理。
  60. //
  61. template<typename _Input_t, typename _Callable_t>
  62. __declspec(noinline)
  63. auto tostring_async(_Input_t&& value, _Callable_t&& callback)
  64. //-> typename modern_callback_adapter_t<std::decay_t<_Callable_t>, std::string>::return_type
  65. {
  66. using _Result_t = std::string;
  67. //适配器类型
  68. using _Adapter_t = modern_callback_adapter_t<std::decay_t<_Callable_t>, _Result_t>;
  69. //通过适配器获得兼容_Callable_t类型的真正的回调,以及返回值_Return_t
  70. auto adapter = typename _Adapter_t::traits(std::forward<_Callable_t>(callback));
  71. //real_callback与callback未必是同一个变量,甚至未必是同一个类型
  72. std::thread([real_callback = std::move(std::get<0>(adapter)), value = std::forward<_Input_t>(value)]
  73. {
  74. real_callback(std::to_string(value));
  75. }).detach();
  76. //返回适配器的return_type变量
  77. return std::move(std::get<1>(adapter));
  78. }
  79. template<typename _Input_t>
  80. auto tostring_async_future(_Input_t&& value)
  81. {
  82. std::promise<std::string> _promise;
  83. std::future<std::string> _future = _promise.get_future();
  84. std::thread([_promise = std::move(_promise), value = std::forward<_Input_t>(value)]() mutable
  85. {
  86. _promise.set_value(std::to_string(value));
  87. }).detach();
  88. return std::move(_future);
  89. }
  90. //-------------------------------------------------------------------------------------------------
  91. //下面演示如何扩展tostring_async函数,以支持future模式
  92. //一、做一个辅助类
  93. struct use_future_t {};
  94. //二、申明这个辅助类的全局变量。不什么这个变量也行,就是每次要写use_future_t{},麻烦些
  95. //以后就使用use_future,替代tostring_async的callback参数了。
  96. //这个参数其实不需要实质传参,最后会被编译器优化没了。
  97. //仅仅是要指定_Callable_t的类型为use_future_t,
  98. //从而在tostring_async函数内,使用偏特化的modern_callback_adapter_t<use_future_t, ...>而已。
  99. inline constexpr use_future_t use_future{};
  100. //将替换use_future_t的,真正的回调类。
  101. //此回调类,符合tostring_async的_Callable_t函数签名。生成此类的实例作为real_callback交给tostring_async作为异步回调。
  102. //
  103. //future模式下,此类持有一个std::promise<_Result_t>,便于设置值和异常
  104. //而将与promise关联的future作为返回值_Return_t,让tostring_async返回。
  105. template<typename _Result_t>
  106. struct use_future_callback_t
  107. {
  108. using promise_type = std::promise<_Result_t>;
  109. mutable promise_type _promise;
  110. void operator()(_Result_t&& value) const
  111. {
  112. _promise.set_value(value);
  113. }
  114. void operator()(_Result_t&& value, std::exception_ptr&& eptr) const
  115. {
  116. if (eptr != nullptr)
  117. _promise.set_exception(std::forward<std::exception_ptr>(eptr));
  118. else
  119. _promise.set_value(std::forward<_Result_t>(value));
  120. }
  121. };
  122. //偏特化_Callable_t为use_future_t类型的modern_callback_adapter_t
  123. //真正的回调类型是use_future_callback_t,返回类型_Return_t是std::future<_Result_t>。
  124. //配合use_future_callback_t的std::promise<_Result_t>,正好组成一对promise/future对。
  125. //promise在真正的回调里设置结果值;
  126. //future返回给调用者获取结果值。
  127. template<typename _Result_t>
  128. struct modern_callback_adapter_t<use_future_t, _Result_t>
  129. {
  130. using return_type = std::future<_Result_t>;
  131. using callback_type = use_future_callback_t<_Result_t>;
  132. static std::tuple<callback_type, return_type> traits(const use_future_t&/*没人关心这个变量*/)
  133. {
  134. callback_type real_callback{};
  135. return_type future = real_callback._promise.get_future();
  136. return { std::move(real_callback), std::move(future) };
  137. }
  138. };
  139. //-------------------------------------------------------------------------------------------------
  140. //同理,可以制作支持C++20的协程的下列一系列类(其实,这才是我的最终目的)
  141. struct use_awaitable_t {};
  142. inline constexpr use_awaitable_t use_awaitable{};
  143. template<typename _Result_t>
  144. struct use_awaitable_callback_t
  145. {
  146. using promise_type = resumef::promise_t<_Result_t>;
  147. using state_type = typename promise_type::state_type;
  148. resumef::counted_ptr<state_type> _state;
  149. void operator()(_Result_t&& value) const
  150. {
  151. _state->set_value(std::forward<_Result_t>(value));
  152. }
  153. void operator()(_Result_t&& value, std::exception_ptr&& eptr) const
  154. {
  155. if (eptr != nullptr)
  156. _state->set_exception(std::forward<std::exception_ptr>(eptr));
  157. else
  158. _state->set_value(std::forward<_Result_t>(value));
  159. }
  160. };
  161. template<typename _Result_t>
  162. struct modern_callback_adapter_t<use_awaitable_t, _Result_t>
  163. {
  164. using promise_type = resumef::promise_t<_Result_t>;
  165. using return_type = resumef::future_t<_Result_t>;
  166. using callback_type = use_awaitable_callback_t<_Result_t>;
  167. static std::tuple<callback_type, return_type> traits(const use_awaitable_t&)
  168. {
  169. promise_type promise;
  170. return { callback_type{ promise._state }, promise.get_future() };
  171. }
  172. };
  173. //所以,我现在的看法是,支持异步操作的库,尽可能如此设计回调。这样便于支持C++20的协程。以及future::then这样的任务链。
  174. //这才是“摩登C++”!
  175. //使用范例
  176. __declspec(noinline)
  177. void resumable_main_modern_cb()
  178. {
  179. using namespace std::literals;
  180. //使用lambda作为异步回调函数,传统用法
  181. //tostring_async_originalism(-1.0, [](std::string && value)
  182. // {
  183. // std::cout << value << std::endl;
  184. // });
  185. tostring_async(1.0, [](std::string && value)
  186. {
  187. std::cout << value << std::endl;
  188. });
  189. /*
  190. std::cout << nocare << std::endl;
  191. std::this_thread::sleep_for(1s);
  192. std::cout << "......" << std::endl;
  193. //支持future的用法
  194. std::future<std::string> f1 = tostring_async_future(5);
  195. std::cout << f1.get() << std::endl;
  196. std::future<std::string> f2 = tostring_async(6.0f, use_future);
  197. std::cout << f2.get() << std::endl;
  198. //支持librf的用法
  199. GO
  200. {
  201. std::string result = co_await tostring_async(10.0, use_awaitable);
  202. std::cout << result << std::endl;
  203. };
  204. resumef::this_scheduler()->run_until_notask();
  205. */
  206. }