scheduler.hpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. // Copyright (C) 2014 Vicente J. Botet Escriba
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. //
  6. #ifndef BOOST_THREAD_EXECUTORS_SCHEDULER_HPP
  7. #define BOOST_THREAD_EXECUTORS_SCHEDULER_HPP
  8. #include <boost/thread/detail/config.hpp>
  9. #if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
  10. #include <boost/thread/executors/detail/scheduled_executor_base.hpp>
  11. #include <boost/chrono/time_point.hpp>
  12. #include <boost/chrono/duration.hpp>
  13. #include <boost/chrono/system_clocks.hpp>
  14. #include <boost/config/abi_prefix.hpp>
  15. #if defined(BOOST_MSVC)
  16. # pragma warning(push)
  17. # pragma warning(disable: 4355) // 'this' : used in base member initializer list
  18. #endif
  19. namespace boost
  20. {
  21. namespace executors
  22. {
  23. /// Wraps the reference to an executor and a function to make a work that submit the function using the executor.
  24. template <class Executor, class Function>
  25. class resubmitter
  26. {
  27. public:
  28. resubmitter(Executor& ex, Function funct) :
  29. ex(ex),
  30. funct(boost::move(funct))
  31. {}
  32. void operator()()
  33. {
  34. ex.submit(funct);
  35. }
  36. private:
  37. Executor& ex;
  38. Function funct;
  39. };
  40. /// resubmitter factory
  41. template <class Executor, class Function>
  42. resubmitter<Executor, typename decay<Function>::type>
  43. resubmit(Executor& ex, BOOST_THREAD_FWD_REF(Function) funct) {
  44. return resubmitter<Executor, typename decay<Function>::type >(ex, boost::move(funct));
  45. }
  46. /// Wraps references to a @c Scheduler and an @c Executor providing an @c Executor that
  47. /// resubmit the function using the referenced Executor at a given @c time_point known at construction.
  48. template <class Scheduler, class Executor>
  49. class resubmit_at_executor
  50. {
  51. public:
  52. typedef typename Scheduler::clock clock;
  53. typedef typename Scheduler::work work;
  54. template <class Duration>
  55. resubmit_at_executor(Scheduler& sch, Executor& ex, chrono::time_point<clock, Duration> const& tp) :
  56. sch(sch),
  57. ex(ex),
  58. tp(tp),
  59. is_closed(false)
  60. {
  61. }
  62. ~resubmit_at_executor()
  63. {
  64. close();
  65. }
  66. template <class Work>
  67. void submit(BOOST_THREAD_FWD_REF(Work) w)
  68. {
  69. if (closed())
  70. {
  71. BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
  72. }
  73. sch.submit_at(resubmit(ex,boost::forward<Work>(w)), tp);
  74. }
  75. Executor& underlying_executor()
  76. {
  77. return ex;
  78. }
  79. Scheduler& underlying_scheduler()
  80. {
  81. return sch;
  82. }
  83. void close()
  84. {
  85. is_closed = true;
  86. }
  87. bool closed()
  88. {
  89. return is_closed || sch.closed() || ex.closed();
  90. }
  91. private:
  92. Scheduler& sch;
  93. Executor& ex;
  94. typename clock::time_point tp;
  95. bool is_closed;
  96. };
  97. /// Expression template helper storing a pair of references to an @c Scheduler and an @c Executor
  98. /// It provides factory helper functions such as at/after that convert these a pair of @c Scheduler @c Executor
  99. /// into an new @c Executor that submit the work using the referenced @c Executor at/after a specific time/duration
  100. /// respectively, using the referenced @Scheduler.
  101. template <class Scheduler, class Executor>
  102. class scheduler_executor_wrapper
  103. {
  104. public:
  105. typedef typename Scheduler::clock clock;
  106. typedef typename Scheduler::work work;
  107. typedef resubmit_at_executor<Scheduler, Executor> the_executor;
  108. scheduler_executor_wrapper(Scheduler& sch, Executor& ex) :
  109. sch(sch),
  110. ex(ex)
  111. {}
  112. ~scheduler_executor_wrapper()
  113. {
  114. }
  115. Executor& underlying_executor()
  116. {
  117. return ex;
  118. }
  119. Scheduler& underlying_scheduler()
  120. {
  121. return sch;
  122. }
  123. template <class Rep, class Period>
  124. the_executor after(chrono::duration<Rep,Period> const& rel_time)
  125. {
  126. return at(clock::now() + rel_time );
  127. }
  128. template <class Duration>
  129. the_executor at(chrono::time_point<clock,Duration> const& abs_time)
  130. {
  131. return the_executor(sch, ex, abs_time);
  132. }
  133. private:
  134. Scheduler& sch;
  135. Executor& ex;
  136. }; //end class
  137. /// Wraps a reference to a @c Scheduler providing an @c Executor that
  138. /// run the function at a given @c time_point known at construction.
  139. template <class Scheduler>
  140. class at_executor
  141. {
  142. public:
  143. typedef typename Scheduler::clock clock;
  144. typedef typename Scheduler::work work;
  145. typedef typename clock::time_point time_point;
  146. template <class Duration>
  147. at_executor(Scheduler& sch, chrono::time_point<clock,Duration> const& tp) :
  148. sch(sch),
  149. tp(tp),
  150. is_closed(false)
  151. {}
  152. ~at_executor()
  153. {
  154. close();
  155. }
  156. Scheduler& underlying_scheduler()
  157. {
  158. return sch;
  159. }
  160. void close()
  161. {
  162. is_closed = true;
  163. }
  164. bool closed()
  165. {
  166. return is_closed || sch.closed();
  167. }
  168. template <class Work>
  169. void submit(BOOST_THREAD_FWD_REF(Work) w)
  170. {
  171. if (closed())
  172. {
  173. BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
  174. }
  175. sch.submit_at(boost::forward<Work>(w), tp);
  176. }
  177. template <class Executor>
  178. resubmit_at_executor<Scheduler, Executor> on(Executor& ex)
  179. {
  180. return resubmit_at_executor<Scheduler, Executor>(sch, ex, tp);
  181. }
  182. private:
  183. Scheduler& sch;
  184. time_point tp;
  185. bool is_closed;
  186. }; //end class
  187. /// A @c Scheduler using a specific thread. Note that a Scheduler is not an Executor.
  188. /// It provides factory helper functions such as at/after that convert a @c Scheduler into an @c Executor
  189. /// that submit the work at/after a specific time/duration respectively.
  190. template <class Clock = chrono::steady_clock>
  191. class scheduler : public detail::scheduled_executor_base<Clock>
  192. {
  193. public:
  194. typedef typename detail::scheduled_executor_base<Clock>::work work;
  195. typedef Clock clock;
  196. scheduler()
  197. : super(),
  198. thr(&super::loop, this) {}
  199. ~scheduler()
  200. {
  201. this->close();
  202. thr.interrupt();
  203. thr.join();
  204. }
  205. template <class Ex>
  206. scheduler_executor_wrapper<scheduler, Ex> on(Ex& ex)
  207. {
  208. return scheduler_executor_wrapper<scheduler, Ex>(*this, ex);
  209. }
  210. template <class Rep, class Period>
  211. at_executor<scheduler> after(chrono::duration<Rep,Period> const& rel_time)
  212. {
  213. return at(rel_time + clock::now());
  214. }
  215. template <class Duration>
  216. at_executor<scheduler> at(chrono::time_point<clock,Duration> const& tp)
  217. {
  218. return at_executor<scheduler>(*this, tp);
  219. }
  220. private:
  221. typedef detail::scheduled_executor_base<Clock> super;
  222. thread thr;
  223. };
  224. }
  225. using executors::resubmitter;
  226. using executors::resubmit;
  227. using executors::resubmit_at_executor;
  228. using executors::scheduler_executor_wrapper;
  229. using executors::at_executor;
  230. using executors::scheduler;
  231. }
  232. #if defined(BOOST_MSVC)
  233. # pragma warning(pop)
  234. #endif
  235. #include <boost/config/abi_suffix.hpp>
  236. #endif
  237. #endif