dlib C++ Library - timer_heavy.h

// Copyright (C) 2005 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_TIMER_KERNEl_1_
#define DLIB_TIMER_KERNEl_1_
#include "../threads.h"
#include "../algs.h"
#include "../misc_api.h"
#include "timer_abstract.h"
namespace dlib
{
 template <
 typename T
 >
 class timer_heavy
 {
 /*!
 WHAT THIS OBJECT REPRESENTS
 This is an implementation of the timer_abstract.h interface. It is very
 simple and uses only one thread which is always alive in a timer_heavy.
 The reason this object exists is for historical reasons. Originally, the
 dlib::timer was a multi-implementation component and the timer_heavy was
 its first implementation. It was superseded later by the more efficient
 dlib::timer. However, timer_heavy is still around so that
 dlib::timer::kernel_1a has something to refer to. This way, old client
 code which somehow depends on the same thread always calling a timer action
 function isn't going to be disrupted.
 INITIAL VALUE
 - running == false
 - delay == 1000
 - ao == a pointer to the action_object()
 - af == a pointer to the action_function()
 - m == a mutex that locks everything in this class
 - s == a signaler for mutex m
 - stop_running == false
 CONVENTION
 - running && !stop_running == is_running()
 - delay == delay_time()
 - *ao == action_object()
 - af == action_function() 
 - if (running) then
 - there is a thread running
 - if (is_running()) then
 - next_time_to_run == the time when the next execution of the action
 function should occur. (the time is given by ts.get_timestamp())
 - stop_running is used to tell the thread to quit. If it is
 set to true then the thread should end.
 !*/
 public:
 typedef void (T::*af_type)();
 timer_heavy( 
 T& ao_,
 af_type af_
 );
 virtual ~timer_heavy(
 );
 void clear(
 );
 af_type action_function (
 ) const;
 const T& action_object (
 ) const;
 T& action_object (
 );
 bool is_running (
 ) const;
 unsigned long delay_time (
 ) const;
 void set_delay_time (
 unsigned long milliseconds
 );
 
 void start ( 
 );
 void stop (
 );
 void stop_and_wait (
 );
 private:
 void thread (
 );
 /*!
 requires
 - is run in its own thread
 ensures
 - calls the action function for the given timer object in the manner
 specified by timer_kernel_abstract.h
 !*/
 // data members
 T& ao;
 const af_type af;
 unsigned long delay;
 mutex m;
 signaler s;
 bool running;
 bool stop_running;
 timestamper ts;
 uint64 next_time_to_run;
 // restricted functions
 timer_heavy(const timer_heavy<T>&); // copy constructor
 timer_heavy<T>& operator=(const timer_heavy<T>&); // assignment operator
 }; 
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
 // member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
 
 template <
 typename T
 >
 timer_heavy<T>::
 timer_heavy( 
 T& ao_,
 af_type af_
 ) : 
 ao(ao_),
 af(af_),
 delay(1000),
 s(m),
 running(false),
 stop_running(false)
 {
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T
 >
 timer_heavy<T>::
 ~timer_heavy(
 )
 {
 stop_and_wait();
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T
 >
 void timer_heavy<T>::
 clear(
 )
 {
 m.lock();
 stop_running = true;
 delay = 1000; 
 s.broadcast();
 m.unlock();
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T
 >
 typename timer_heavy<T>::af_type timer_heavy<T>::
 action_function (
 ) const
 {
 return af;
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T
 >
 const T& timer_heavy<T>::
 action_object (
 ) const
 {
 return ao;
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T
 >
 T& timer_heavy<T>::
 action_object (
 )
 {
 return ao;
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T
 >
 bool timer_heavy<T>::
 is_running (
 ) const
 {
 auto_mutex M(m);
 return running && !stop_running;
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T
 >
 unsigned long timer_heavy<T>::
 delay_time (
 ) const
 {
 auto_mutex M(m);
 return delay; 
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T
 >
 void timer_heavy<T>::
 set_delay_time (
 unsigned long milliseconds
 )
 {
 m.lock();
 // if (is_running()) then we should adjust next_time_to_run
 if (running && !stop_running)
 {
 next_time_to_run -= delay*1000;
 next_time_to_run += milliseconds*1000;
 }
 delay = milliseconds;
 s.broadcast();
 m.unlock();
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T
 >
 void timer_heavy<T>::
 start ( 
 )
 {
 auto_mutex M(m);
 // if (is_running() == false) then reset the countdown to the next call 
 // to the action_function()
 if ( (running && !stop_running) == false)
 next_time_to_run = ts.get_timestamp() + delay*1000;
 stop_running = false;
 if (running == false)
 {
 running = true;
 // start the thread
 if (create_new_thread<timer_heavy,&timer_heavy::thread>(*this) == false)
 {
 running = false;
 throw dlib::thread_error("error creating new thread in timer_heavy::start");
 }
 }
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T
 >
 void timer_heavy<T>::
 stop (
 )
 {
 m.lock();
 stop_running = true;
 s.broadcast();
 m.unlock();
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T
 >
 void timer_heavy<T>::
 thread (
 )
 {
 auto_mutex M(m);
 unsigned long delay_remaining;
 uint64 current_time = ts.get_timestamp();
 if (current_time < next_time_to_run)
 delay_remaining = static_cast<unsigned long>((next_time_to_run-current_time)/1000);
 else
 delay_remaining = 0;
 while (stop_running == false)
 {
 if (delay_remaining > 0)
 s.wait_or_timeout(delay_remaining);
 if (stop_running)
 break; 
 current_time = ts.get_timestamp();
 if (current_time < next_time_to_run)
 {
 // then we woke up too early so we should keep waiting
 delay_remaining = static_cast<unsigned long>((next_time_to_run-current_time)/1000);
 // rounding might make this be zero anyway. So if it is
 // then we will say we have hit the next time to run.
 if (delay_remaining > 0)
 continue;
 }
 // call the action function 
 m.unlock();
 (ao.*af)(); 
 m.lock();
 current_time = ts.get_timestamp();
 next_time_to_run = current_time + delay*1000;
 delay_remaining = delay;
 }
 running = false;
 stop_running = false;
 s.broadcast();
 }
// ----------------------------------------------------------------------------------------
 template <
 typename T
 >
 void timer_heavy<T>::
 stop_and_wait (
 )
 {
 m.lock();
 if (running)
 {
 // make the running thread terminate
 stop_running = true;
 s.broadcast();
 // wait for the thread to quit
 while (running)
 s.wait(); 
 }
 m.unlock();
 }
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_TIMER_KERNEl_1_

AltStyle によって変換されたページ (->オリジナル) /