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: |
34 | resubmitter(Executor& ex, Function funct) : |
35 | ex(ex), |
36 | funct(boost::move(funct)) |
37 | {} |
38 | |
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> |
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> |
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 | |
74 | ~resubmit_at_executor() |
75 | { |
76 | close(); |
77 | } |
78 | |
79 | template <class Work> |
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 | |
89 | Executor& underlying_executor() |
90 | { |
91 | return ex; |
92 | } |
93 | Scheduler& underlying_scheduler() |
94 | { |
95 | return sch; |
96 | } |
97 | |
98 | void close() |
99 | { |
100 | is_closed = true; |
101 | } |
102 | |
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 | |
128 | scheduler_executor_wrapper(Scheduler& sch, Executor& ex) : |
129 | sch(sch), |
130 | ex(ex) |
131 | {} |
132 | |
133 | ~scheduler_executor_wrapper() |
134 | { |
135 | } |
136 | |
137 | Executor& underlying_executor() |
138 | { |
139 | return ex; |
140 | } |
141 | Scheduler& underlying_scheduler() |
142 | { |
143 | return sch; |
144 | } |
145 | |
146 | template <class Rep, class Period> |
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> |
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> |
174 | at_executor(Scheduler& sch, chrono::time_point<clock,Duration> const& tp) : |
175 | sch(sch), |
176 | tp(tp), |
177 | is_closed(false) |
178 | {} |
179 | |
180 | ~at_executor() |
181 | { |
182 | close(); |
183 | } |
184 | |
185 | Scheduler& underlying_scheduler() |
186 | { |
187 | return sch; |
188 | } |
189 | |
190 | void close() |
191 | { |
192 | is_closed = true; |
193 | } |
194 | |
195 | bool closed() |
196 | { |
197 | return is_closed || sch.closed(); |
198 | } |
199 | |
200 | template <class Work> |
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> |
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 | |
233 | scheduler() |
234 | : super(), |
235 | thr(&super::loop, this) {} |
236 | |
237 | ~scheduler() |
238 | { |
239 | this->close(); |
240 | thr.interrupt(); |
241 | thr.join(); |
242 | } |
243 | template <class 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> |
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> |
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 | |