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