1 // Copyright (C) 2005 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 #ifndef DLIB_TIMER_KERNEl_1_ 4 #define DLIB_TIMER_KERNEl_1_ 5 6 #include "../threads.h" 7 #include "../algs.h" 8 #include "../misc_api.h" 9 #include "timer_abstract.h" 10 11 namespace dlib 12 { 13 14 template < 15 typename T 16 > 17 class timer_heavy 18 { 19 /*! 20 WHAT THIS OBJECT REPRESENTS 21 This is an implementation of the timer_abstract.h interface. It is very 22 simple and uses only one thread which is always alive in a timer_heavy. 23 The reason this object exists is for historical reasons. Originally, the 24 dlib::timer was a multi-implementation component and the timer_heavy was 25 its first implementation. It was superseded later by the more efficient 26 dlib::timer. However, timer_heavy is still around so that 27 dlib::timer::kernel_1a has something to refer to. This way, old client 28 code which somehow depends on the same thread always calling a timer action 29 function isn't going to be disrupted. 30 31 32 INITIAL VALUE 33 - running == false 34 - delay == 1000 35 - ao == a pointer to the action_object() 36 - af == a pointer to the action_function() 37 - m == a mutex that locks everything in this class 38 - s == a signaler for mutex m 39 - stop_running == false 40 41 CONVENTION 42 - running && !stop_running == is_running() 43 - delay == delay_time() 44 - *ao == action_object() 45 - af == action_function() 46 47 - if (running) then 48 - there is a thread running 49 - if (is_running()) then 50 - next_time_to_run == the time when the next execution of the action 51 function should occur. (the time is given by ts.get_timestamp()) 52 53 - stop_running is used to tell the thread to quit. If it is 54 set to true then the thread should end. 55 !*/ 56 57 public: 58 59 typedef void (T::*af_type)(); 60 61 timer_heavy( 62 T& ao_, 63 af_type af_ 64 ); 65 66 virtual ~timer_heavy( 67 ); 68 69 void clear( 70 ); 71 72 af_type action_function ( 73 ) const; 74 75 const T& action_object ( 76 ) const; 77 78 T& action_object ( 79 ); 80 81 bool is_running ( 82 ) const; 83 84 unsigned long delay_time ( 85 ) const; 86 87 void set_delay_time ( 88 unsigned long milliseconds 89 ); 90 91 void start ( 92 ); 93 94 void stop ( 95 ); 96 97 void stop_and_wait ( 98 ); 99 100 private: 101 102 void thread ( 103 ); 104 /*! 105 requires 106 - is run in its own thread 107 ensures 108 - calls the action function for the given timer object in the manner 109 specified by timer_kernel_abstract.h 110 !*/ 111 112 // data members 113 T& ao; 114 const af_type af; 115 unsigned long delay; 116 mutex m; 117 signaler s; 118 119 bool running; 120 bool stop_running; 121 timestamper ts; 122 uint64 next_time_to_run; 123 124 // restricted functions 125 timer_heavy(const timer_heavy<T>&); // copy constructor 126 timer_heavy<T>& operator=(const timer_heavy<T>&); // assignment operator 127 128 }; 129 130 // ---------------------------------------------------------------------------------------- 131 // ---------------------------------------------------------------------------------------- 132 // member function definitions 133 // ---------------------------------------------------------------------------------------- 134 // ---------------------------------------------------------------------------------------- 135 136 template < 137 typename T 138 > 139 timer_heavy<T>:: timer_heavy(T & ao_,af_type af_)140 timer_heavy( 141 T& ao_, 142 af_type af_ 143 ) : 144 ao(ao_), 145 af(af_), 146 delay(1000), 147 s(m), 148 running(false), 149 stop_running(false) 150 { 151 } 152 153 // ---------------------------------------------------------------------------------------- 154 155 template < 156 typename T 157 > 158 timer_heavy<T>:: ~timer_heavy()159 ~timer_heavy( 160 ) 161 { 162 stop_and_wait(); 163 } 164 165 // ---------------------------------------------------------------------------------------- 166 167 template < 168 typename T 169 > 170 void timer_heavy<T>:: clear()171 clear( 172 ) 173 { 174 m.lock(); 175 stop_running = true; 176 delay = 1000; 177 s.broadcast(); 178 m.unlock(); 179 } 180 181 // ---------------------------------------------------------------------------------------- 182 183 template < 184 typename T 185 > 186 typename timer_heavy<T>::af_type timer_heavy<T>:: action_function()187 action_function ( 188 ) const 189 { 190 return af; 191 } 192 193 // ---------------------------------------------------------------------------------------- 194 195 template < 196 typename T 197 > 198 const T& timer_heavy<T>:: action_object()199 action_object ( 200 ) const 201 { 202 return ao; 203 } 204 205 // ---------------------------------------------------------------------------------------- 206 207 template < 208 typename T 209 > 210 T& timer_heavy<T>:: action_object()211 action_object ( 212 ) 213 { 214 return ao; 215 } 216 217 // ---------------------------------------------------------------------------------------- 218 219 template < 220 typename T 221 > 222 bool timer_heavy<T>:: is_running()223 is_running ( 224 ) const 225 { 226 auto_mutex M(m); 227 return running && !stop_running; 228 } 229 230 // ---------------------------------------------------------------------------------------- 231 232 template < 233 typename T 234 > 235 unsigned long timer_heavy<T>:: delay_time()236 delay_time ( 237 ) const 238 { 239 auto_mutex M(m); 240 return delay; 241 } 242 243 // ---------------------------------------------------------------------------------------- 244 245 template < 246 typename T 247 > 248 void timer_heavy<T>:: set_delay_time(unsigned long milliseconds)249 set_delay_time ( 250 unsigned long milliseconds 251 ) 252 { 253 m.lock(); 254 255 // if (is_running()) then we should adjust next_time_to_run 256 if (running && !stop_running) 257 { 258 next_time_to_run -= delay*1000; 259 next_time_to_run += milliseconds*1000; 260 } 261 262 delay = milliseconds; 263 s.broadcast(); 264 m.unlock(); 265 } 266 267 // ---------------------------------------------------------------------------------------- 268 269 template < 270 typename T 271 > 272 void timer_heavy<T>:: start()273 start ( 274 ) 275 { 276 auto_mutex M(m); 277 278 // if (is_running() == false) then reset the countdown to the next call 279 // to the action_function() 280 if ( (running && !stop_running) == false) 281 next_time_to_run = ts.get_timestamp() + delay*1000; 282 283 stop_running = false; 284 if (running == false) 285 { 286 running = true; 287 288 // start the thread 289 if (create_new_thread<timer_heavy,&timer_heavy::thread>(*this) == false) 290 { 291 running = false; 292 throw dlib::thread_error("error creating new thread in timer_heavy::start"); 293 } 294 } 295 } 296 297 // ---------------------------------------------------------------------------------------- 298 299 template < 300 typename T 301 > 302 void timer_heavy<T>:: stop()303 stop ( 304 ) 305 { 306 m.lock(); 307 stop_running = true; 308 s.broadcast(); 309 m.unlock(); 310 } 311 312 // ---------------------------------------------------------------------------------------- 313 314 template < 315 typename T 316 > 317 void timer_heavy<T>:: thread()318 thread ( 319 ) 320 { 321 auto_mutex M(m); 322 unsigned long delay_remaining; 323 uint64 current_time = ts.get_timestamp(); 324 325 if (current_time < next_time_to_run) 326 delay_remaining = static_cast<unsigned long>((next_time_to_run-current_time)/1000); 327 else 328 delay_remaining = 0; 329 330 while (stop_running == false) 331 { 332 if (delay_remaining > 0) 333 s.wait_or_timeout(delay_remaining); 334 335 if (stop_running) 336 break; 337 338 current_time = ts.get_timestamp(); 339 if (current_time < next_time_to_run) 340 { 341 // then we woke up too early so we should keep waiting 342 delay_remaining = static_cast<unsigned long>((next_time_to_run-current_time)/1000); 343 344 // rounding might make this be zero anyway. So if it is 345 // then we will say we have hit the next time to run. 346 if (delay_remaining > 0) 347 continue; 348 } 349 350 // call the action function 351 m.unlock(); 352 (ao.*af)(); 353 m.lock(); 354 355 current_time = ts.get_timestamp(); 356 next_time_to_run = current_time + delay*1000; 357 delay_remaining = delay; 358 } 359 running = false; 360 stop_running = false; 361 s.broadcast(); 362 } 363 364 // ---------------------------------------------------------------------------------------- 365 366 template < 367 typename T 368 > 369 void timer_heavy<T>:: stop_and_wait()370 stop_and_wait ( 371 ) 372 { 373 m.lock(); 374 if (running) 375 { 376 // make the running thread terminate 377 stop_running = true; 378 379 s.broadcast(); 380 // wait for the thread to quit 381 while (running) 382 s.wait(); 383 } 384 m.unlock(); 385 } 386 387 // ---------------------------------------------------------------------------------------- 388 389 } 390 391 #endif // DLIB_TIMER_KERNEl_1_ 392 393