1 // Copyright (C) 2007 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 #ifndef DLIB_TIMEr_Hh_ 4 #define DLIB_TIMEr_Hh_ 5 6 #include <memory> 7 8 #include "../threads.h" 9 #include "../algs.h" 10 #include "../misc_api.h" 11 #include "timer_abstract.h" 12 #include "../uintn.h" 13 #include "../binary_search_tree.h" 14 #include "timer_heavy.h" 15 16 namespace dlib 17 { 18 19 struct timer_base : public threaded_object 20 { 21 /*! 22 WHAT THIS OBJECT REPRESENTS 23 This object contains the base members of the timer object. 24 It exists so that we can access them from outside any templated functions. 25 !*/ 26 27 unsigned long delay; 28 // these are only modified by the global_clock 29 uint64 next_time_to_run; 30 timestamper ts; 31 bool running; 32 bool in_global_clock; 33 }; 34 35 // ---------------------------------------------------------------------------------------- 36 37 class timer_global_clock : private threaded_object 38 { 39 /*! 40 This object sets up a timer that triggers the action function 41 for timer objects that are tracked inside this object. 42 INITIAL VALUE 43 - shutdown == false 44 - running == false 45 46 CONVENTION 47 - if (shutdown) then 48 - thread() should terminate 49 - else (running) then 50 - thread() is running 51 52 - tm[time] == pointer to a timer_base object 53 !*/ 54 typedef binary_search_tree<uint64,timer_base*,memory_manager<char>::kernel_2b>::kernel_2a_c time_map; 55 public: 56 57 ~timer_global_clock(); 58 59 void add ( 60 timer_base* r 61 ); 62 /*! 63 requires 64 - m is locked 65 ensures 66 - starts the thread if it isn't already started 67 - adds r to tm 68 - #r->in_global_clock == true 69 - updates r->next_time_to_run appropriately according to 70 r->delay 71 !*/ 72 73 void remove ( 74 timer_base* r 75 ); 76 /*! 77 requires 78 - m is locked 79 ensures 80 - if (r is in tm) then 81 - removes r from tm 82 - #r->in_global_clock == false 83 !*/ 84 85 void adjust_delay ( 86 timer_base* r, 87 unsigned long new_delay 88 ); 89 /*! 90 requires 91 - m is locked 92 ensures 93 - #r->delay == new_delay 94 - if (r->in_global_clock) then 95 - the time to the next event will have been appropriately adjusted 96 !*/ 97 98 mutex m; 99 100 friend std::shared_ptr<timer_global_clock> get_global_clock(); 101 102 private: 103 timer_global_clock(); 104 105 time_map tm; 106 signaler s; 107 bool shutdown; 108 bool running; 109 timestamper ts; 110 111 void thread(); 112 /*! 113 ensures 114 - spawns timer tasks as is appropriate 115 !*/ 116 }; 117 std::shared_ptr<timer_global_clock> get_global_clock(); 118 /*! 119 ensures 120 - returns the global instance of the timer_global_clock object 121 !*/ 122 123 // ---------------------------------------------------------------------------------------- 124 125 template < 126 typename T 127 > 128 class timer : private timer_base 129 { 130 /*! 131 INITIAL VALUE 132 - running == false 133 - delay == 1000 134 - ao == a pointer to the action_object() 135 - af == a pointer to the action_function() 136 - in_global_clock == false 137 - next_time_to_run == 0 138 - gc == get_global_clock() 139 140 CONVENTION 141 - the mutex used to lock everything is gc->m 142 - running == is_running() 143 - delay == delay_time() 144 - *ao == action_object() 145 - af == action_function() 146 - if (!running) then 147 - in_global_clock == false 148 - else 149 - next_time_to_run == the next time this timer should run according 150 to the timestamper in the global_clock 151 !*/ 152 153 public: 154 155 // These typedefs are here for backwards compatibility with previous versions of 156 // dlib. 157 typedef timer_heavy<T> kernel_1a; 158 typedef timer kernel_2a; 159 160 typedef void (T::*af_type)(); 161 162 timer( 163 T& ao_, 164 af_type af_ 165 ); 166 167 virtual ~timer( 168 ); 169 170 void clear( 171 ); 172 173 af_type action_function ( 174 ) const; 175 176 const T& action_object ( 177 ) const; 178 179 T& action_object ( 180 ); 181 182 bool is_running ( 183 ) const; 184 185 unsigned long delay_time ( 186 ) const; 187 188 void set_delay_time ( 189 unsigned long milliseconds 190 ); 191 192 void start ( 193 ); 194 195 void stop ( 196 ); 197 198 void stop_and_wait ( 199 ); 200 201 private: 202 203 void thread ( 204 ); 205 /*! 206 ensures 207 - calls the action function 208 !*/ 209 210 // data members 211 T& ao; 212 const af_type af; 213 std::shared_ptr<timer_global_clock> gc; 214 215 // restricted functions 216 timer(const timer&); // copy constructor 217 timer& operator=(const timer&); // assignment operator 218 219 }; 220 221 // ---------------------------------------------------------------------------------------- 222 // ---------------------------------------------------------------------------------------- 223 // member function definitions 224 // ---------------------------------------------------------------------------------------- 225 // ---------------------------------------------------------------------------------------- 226 227 template < 228 typename T 229 > 230 timer<T>:: timer(T & ao_,af_type af_)231 timer( 232 T& ao_, 233 af_type af_ 234 ) : 235 ao(ao_), 236 af(af_), 237 gc(get_global_clock()) 238 { 239 delay = 1000; 240 next_time_to_run = 0; 241 running = false; 242 in_global_clock = false; 243 } 244 245 // ---------------------------------------------------------------------------------------- 246 247 template < 248 typename T 249 > 250 timer<T>:: ~timer()251 ~timer( 252 ) 253 { 254 clear(); 255 wait(); 256 } 257 258 // ---------------------------------------------------------------------------------------- 259 260 template < 261 typename T 262 > 263 void timer<T>:: clear()264 clear( 265 ) 266 { 267 auto_mutex M(gc->m); 268 running = false; 269 gc->remove(this); 270 delay = 1000; 271 next_time_to_run = 0; 272 } 273 274 // ---------------------------------------------------------------------------------------- 275 276 template < 277 typename T 278 > 279 typename timer<T>::af_type timer<T>:: action_function()280 action_function ( 281 ) const 282 { 283 return af; 284 } 285 286 // ---------------------------------------------------------------------------------------- 287 288 template < 289 typename T 290 > 291 const T& timer<T>:: action_object()292 action_object ( 293 ) const 294 { 295 return ao; 296 } 297 298 // ---------------------------------------------------------------------------------------- 299 300 template < 301 typename T 302 > 303 T& timer<T>:: action_object()304 action_object ( 305 ) 306 { 307 return ao; 308 } 309 310 // ---------------------------------------------------------------------------------------- 311 312 template < 313 typename T 314 > 315 bool timer<T>:: is_running()316 is_running ( 317 ) const 318 { 319 auto_mutex M(gc->m); 320 return running; 321 } 322 323 // ---------------------------------------------------------------------------------------- 324 325 template < 326 typename T 327 > 328 unsigned long timer<T>:: delay_time()329 delay_time ( 330 ) const 331 { 332 auto_mutex M(gc->m); 333 return delay; 334 } 335 336 // ---------------------------------------------------------------------------------------- 337 338 template < 339 typename T 340 > 341 void timer<T>:: set_delay_time(unsigned long milliseconds)342 set_delay_time ( 343 unsigned long milliseconds 344 ) 345 { 346 auto_mutex M(gc->m); 347 gc->adjust_delay(this,milliseconds); 348 } 349 350 // ---------------------------------------------------------------------------------------- 351 352 template < 353 typename T 354 > 355 void timer<T>:: start()356 start ( 357 ) 358 { 359 auto_mutex M(gc->m); 360 if (!running) 361 { 362 gc->add(this); 363 running = true; 364 } 365 } 366 367 // ---------------------------------------------------------------------------------------- 368 369 template < 370 typename T 371 > 372 void timer<T>:: stop()373 stop ( 374 ) 375 { 376 gc->m.lock(); 377 running = false; 378 gc->remove(this); 379 gc->m.unlock(); 380 } 381 382 // ---------------------------------------------------------------------------------------- 383 384 template < 385 typename T 386 > 387 void timer<T>:: thread()388 thread ( 389 ) 390 { 391 // call the action function 392 (ao.*af)(); 393 auto_mutex M(gc->m); 394 if (running) 395 { 396 gc->remove(this); 397 gc->add(this); 398 } 399 } 400 401 // ---------------------------------------------------------------------------------------- 402 403 template < 404 typename T 405 > 406 void timer<T>:: stop_and_wait()407 stop_and_wait ( 408 ) 409 { 410 gc->m.lock(); 411 running = false; 412 gc->remove(this); 413 gc->m.unlock(); 414 wait(); 415 } 416 417 // ---------------------------------------------------------------------------------------- 418 419 } 420 421 #ifdef NO_MAKEFILE 422 #include "timer.cpp" 423 #endif 424 425 #endif // DLIB_TIMEr_Hh_ 426 427 428