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