Ticket #13473: basic_repeating_timer.hpp

File basic_repeating_timer.hpp, 7.3 KB (added by Mike Haben <michael.haben@…>, 5 years ago)

Third-party boost::asio repeating timer

Line 
1#ifndef BOOST_ASIO_REPEATING_TIMER_H_INCLUDED
2#define BOOST_ASIO_REPEATING_TIMER_H_INCLUDED
3
4// Developed 2007 by David C. Wyles (http:///www.codegorilla.co.uk)
5// released for public consumption under the same
6// licensing policy as the boost library http://www.boost.org/LICENSE_1_0.txt
7//
8// most people will use the repeating_timer typedef for working with posix time
9//
10// Is is based on the basic_deadline_timer
11//
12
13#include <boost/bind.hpp>
14#include <boost/noncopyable.hpp>
15#include <boost/asio.hpp>
16#include <boost/date_time/posix_time/posix_time.hpp>
17#include <boost/thread/recursive_mutex.hpp>
18#include <boost/thread/condition.hpp>
19#include <boost/shared_ptr.hpp>
20#include <boost/enable_shared_from_this.hpp>
21#include <boost/weak_ptr.hpp>
22
23namespace boost
24{
25namespace asio
26{
27 // basic repeating timer with start stop semantics.
28
29 template <typename Time,
30 typename TimeTraits = boost::asio::time_traits<Time>,
31 typename TimerService = boost::asio::deadline_timer_service<Time, TimeTraits> >
32 class basic_repeating_timer : public boost::asio::basic_io_object<TimerService>
33 {
34 public:
35 typedef boost::asio::basic_deadline_timer<Time> timer_type;
36
37 explicit basic_repeating_timer( boost::asio::io_service& io_service )
38 : boost::asio::basic_io_object<TimerService>(io_service)
39 {
40 }
41
42 ~basic_repeating_timer()
43 {
44 stop();
45 }
46
47 template <typename WaitHandler>
48 void start( typename timer_type::duration_type const & repeat_interval, WaitHandler handler )
49 {
50 boost::recursive_mutex::scoped_lock guard(lock_);
51 {
52 // cleanup code, cancel any existing timer
53 handler_.reset();
54 if( timer_ )
55 {
56 timer_->cancel();
57 }
58 timer_.reset();
59 }
60
61 // create new handler.
62 handler_.reset( new handler_impl<WaitHandler>( handler ) );
63 // create new timer
64 timer_ = internal_timer::create( this->get_io_service(), repeat_interval, handler_ );
65 }
66
67 void stop()
68 {
69 boost::recursive_mutex::scoped_lock guard(lock_);
70 {
71 // cleanup code.
72 handler_.reset();
73 if( timer_ )
74 {
75 timer_->cancel();
76 }
77 timer_.reset();
78 }
79 }
80
81 void cancel() {stop();}
82
83 // changes the interval the next time the timer is fired.
84 void change_interval( typename timer_type::duration_type const & repeat_interval )
85 {
86 boost::recursive_mutex::scoped_lock guard(lock_);
87 if( timer_ )
88 {
89 timer_->change_interval( repeat_interval );
90 }
91 }
92
93 private:
94
95 boost::recursive_mutex lock_;
96 class internal_timer;
97 typedef boost::shared_ptr<internal_timer> internal_timer_ptr;
98 internal_timer_ptr timer_;
99
100 class handler_base;
101 boost::shared_ptr<handler_base> handler_;
102
103 class handler_base
104 {
105 public:
106 virtual ~handler_base() {}
107 virtual void handler( boost::system::error_code const & ) = 0;
108 };
109
110 template <typename HandlerFunc>
111 class handler_impl : public handler_base
112 {
113 public:
114 handler_impl( HandlerFunc func ) : handler_func_(func) {}
115 virtual void handler( boost::system::error_code const & result )
116 {
117 handler_func_(result);
118 }
119 HandlerFunc handler_func_;
120 };
121
122 class internal_timer : public boost::enable_shared_from_this<internal_timer>
123 {
124 public:
125 static internal_timer_ptr create( boost::asio::io_service& io_service,
126 typename timer_type::duration_type const & repeat_interval,
127 boost::shared_ptr<handler_base> const & handler )
128 {
129 internal_timer_ptr timer( new internal_timer( io_service ) );
130 timer->start( repeat_interval, handler );
131 return timer;
132 }
133
134 void cancel()
135 {
136 boost::recursive_mutex::scoped_lock guard( lock_ );
137 timer_.cancel();
138 }
139
140 void change_interval( typename timer_type::duration_type const & repeat_interval )
141 {
142 boost::recursive_mutex::scoped_lock guard( lock_ );
143 interval_ = repeat_interval;
144 }
145
146 private:
147 timer_type timer_;
148 boost::weak_ptr<handler_base> handler_;
149 typename timer_type::duration_type interval_;
150 boost::recursive_mutex lock_;
151
152 internal_timer( boost::asio::io_service& io_service )
153 :timer_(io_service)
154 {
155 }
156
157 void start( typename timer_type::duration_type const & repeat_interval,
158 boost::shared_ptr<handler_base> const & handler )
159 {
160 // only EVER called once, via create
161 interval_ = repeat_interval;
162 handler_ = handler;
163
164 timer_.expires_from_now( interval_ );
165 timer_.async_wait( boost::bind( &internal_timer::handle_timeout, this->shared_from_this(), boost::asio::placeholders::error ) );
166 }
167
168 void handle_timeout(boost::system::error_code const& error)
169 {
170 // we lock in the timeout to block the cancel operation until this timeout completes
171 boost::recursive_mutex::scoped_lock guard( lock_ );
172 {
173 // do the fire.
174 boost::shared_ptr<handler_base> Handler = handler_.lock();
175 if( Handler )
176 {
177 try
178 {
179 Handler->handler(error);
180 }
181 catch( std::exception const & e )
182 {
183 // consume for now, no much else we can do, we don't want to damage the
184 // io_service thread
185 (void)e;
186 }
187 }
188 }
189
190 if( !error )
191 {
192 // check if we need to reschedule.
193 boost::shared_ptr<handler_base> Handler = handler_.lock();
194 if( Handler )
195 {
196 timer_.expires_from_now( interval_ );
197 //m_Timer.expires_at( m_Timer.expires_at() + m_Repeat_Interval );
198 timer_.async_wait( boost::bind( &internal_timer::handle_timeout, this->shared_from_this(), boost::asio::placeholders::error ) );
199 }
200 }
201 }
202 };
203 };
204
205 typedef basic_repeating_timer<boost::posix_time::ptime> repeating_timer;
206}
207}
208
209#endif
210
211