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.
concurrentqueue/benchmarks/dlib/timer/timer_heavy.h

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_