• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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