dlib C++ Library - timer.cpp

// Copyright (C) 2007 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_TIMER_cPPh_
#define DLIB_TIMER_cPPh_
#include "timer.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
 timer_global_clock::
 timer_global_clock(
 ): 
 s(m),
 shutdown(false),
 running(false)
 {
 }
// ----------------------------------------------------------------------------------------
 timer_global_clock::
 ~timer_global_clock()
 {
 // The only time this destructor is called is when 
 //
 // a) the process terminates
 // b) the dynamic library(.so/.dll) is unloaded (could be a part of a))
 // 
 // in case of a)
 // windows: the process termination is especially painful, since threads are killed
 // before destructors of the process image .dll's are called.
 // Thus, for the windows platform, there is no threads running, so the only thing
 // to do here is just let the standard memberwise destructors run
 // linux: it's ok to just signal shutdown and wait for the running thread, to exit
 // 
 // in case of b)
 // windows:
 // if it's part of the termination process, a) applies
 // if its part of user doing manual load_library/unload_library
 // there is no (safe/robust)solution, but best practices are described here
 // https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971.aspx
 // to support such a clean shutdown, you are required to make a call prior to
 // unload dll, that shutdown all the threads in the contained dll.
 // This could be done in this module by providing a global_delete_clock()
 // 
 // linux: the destructor for linux will do it's usual job regardless.
 //
 #ifndef _WIN32
 m.lock();
 shutdown = true;
 s.signal();
 m.unlock();
 wait();
 #endif
 }
// ----------------------------------------------------------------------------------------
 void timer_global_clock::
 add (
 timer_base* r
 )
 {
 if (r->in_global_clock == false)
 {
 // if the thread isn't running then start it up
 if (!running)
 {
 start();
 running = true;
 }
 uint64 t = ts.get_timestamp() + r->delay*1000;
 tm.reset();
 if (!tm.move_next() || t < tm.element().key())
 {
 // we need to make the thread adjust its next time to
 // trigger if this new event occurrs sooner than the
 // next event in tm
 s.signal();
 }
 timer_base* rtemp = r;
 uint64 ttemp = t;
 tm.add(ttemp,rtemp);
 r->next_time_to_run = t;
 r->in_global_clock = true;
 }
 }
// ----------------------------------------------------------------------------------------
 void timer_global_clock::
 remove (
 timer_base* r
 )
 {
 if (r->in_global_clock)
 {
 tm.position_enumerator(r->next_time_to_run-1);
 do
 {
 if (tm.element().value() == r)
 {
 uint64 t;
 timer_base* rtemp;
 tm.remove_current_element(t,rtemp);
 r->in_global_clock = false;
 break;
 }
 } while (tm.move_next());
 }
 }
// ----------------------------------------------------------------------------------------
 void timer_global_clock::
 adjust_delay (
 timer_base* r,
 unsigned long new_delay
 )
 {
 if (r->in_global_clock)
 {
 remove(r);
 // compute the new next_time_to_run and store it in t
 uint64 t = r->next_time_to_run;
 t -= r->delay*1000;
 t += new_delay*1000;
 tm.reset();
 if (!tm.move_next() || t < tm.element().key())
 {
 // we need to make the thread adjust its next time to
 // trigger if this new event occurrs sooner than the
 // next event in tm
 s.signal();
 }
 // set this incase add throws
 r->running = false;
 r->delay = new_delay;
 timer_base* rtemp = r;
 uint64 ttemp = t;
 tm.add(ttemp,rtemp);
 r->next_time_to_run = t;
 r->in_global_clock = true;
 // put this back now that we know add didn't throw
 r->running = true;
 }
 else
 {
 r->delay = new_delay;
 }
 }
// ----------------------------------------------------------------------------------------
 void timer_global_clock::
 thread()
 {
 auto_mutex M(m);
 while (!shutdown)
 {
 unsigned long delay = 100000;
 tm.reset();
 tm.move_next();
 // loop and start all the action functions for timers that should have
 // triggered.
 while(tm.current_element_valid())
 {
 const uint64 cur_time = ts.get_timestamp();
 uint64 t = tm.element().key();
 // if the next event in tm is ready to trigger
 if (t <= cur_time + 999)
 {
 // remove this event from the tm map
 timer_base* r = tm.element().value();
 timer_base* rtemp;
 tm.remove_current_element(t,rtemp);
 r->in_global_clock = false;
 // if this timer is still "running" then start its action function
 if (r->running)
 {
 r->restart();
 }
 }
 else
 {
 // there aren't any more timers that should trigger so we compute
 // the delay to the next timer event.
 delay = static_cast<unsigned long>((t - cur_time)/1000);
 break;
 }
 }
 s.wait_or_timeout(delay);
 }
 }
// ----------------------------------------------------------------------------------------
 std::shared_ptr<timer_global_clock> get_global_clock()
 {
 static std::shared_ptr<timer_global_clock> d(new timer_global_clock);
 return d;
 }
// ----------------------------------------------------------------------------------------
 // do this just to make sure get_global_clock() gets called at program startup
 class timer_global_clock_helper
 {
 public:
 timer_global_clock_helper()
 {
 get_global_clock();
 }
 };
 static timer_global_clock_helper call_get_global_clock;
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_TIMER_cPPh_

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