You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
393 lines
9.7 KiB
C++
393 lines
9.7 KiB
C++
// 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_
|
|
|