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