00001 #include "PeriodicTimer.hpp" 00002 00003 namespace msp { 00004 00005 PeriodicTimer::PeriodicTimer(std::function<void()> funct, 00006 const double period_seconds) : 00007 funct(funct) { 00008 period_us = 00009 std::chrono::duration<size_t, std::micro>(size_t(period_seconds * 1e6)); 00010 } 00011 00012 bool PeriodicTimer::start() { 00013 // only start thread if period is above 0 00014 if(!(period_us.count() > 0)) return false; 00015 // only start once 00016 if(running_.test_and_set()) return false; 00017 // lock mutex so that the try_lock_until in the new thread always times out 00018 // and loops 00019 mutex_timer.lock(); 00020 // start the thread 00021 thread_ptr = std::shared_ptr<std::thread>(new std::thread([this] { 00022 // log now. 00023 tstart = std::chrono::steady_clock::now(); 00024 while(true) { 00025 // call function 00026 funct(); 00027 // increment the reference time to know when to timeout waiting 00028 tstart += period_us; 00029 // wait until end of period or stop is called 00030 if(mutex_timer.try_lock_until(tstart)) { 00031 // gets here if lock was acquired (means someone called stop and 00032 // manually unlocked the mutex) 00033 mutex_timer.unlock(); 00034 break; 00035 } 00036 } // function over, return 00037 })); 00038 return true; 00039 } 00040 00041 bool PeriodicTimer::stop() { 00042 bool rc = false; 00043 if(running_.test_and_set()) { 00044 // was already running, so let the thread finish 00045 mutex_timer.unlock(); 00046 if(thread_ptr != nullptr && thread_ptr->joinable()) { 00047 thread_ptr->join(); 00048 } 00049 rc = true; 00050 } 00051 running_.clear(); 00052 return rc; 00053 } 00054 00055 void PeriodicTimer::setPeriod(const double& period_seconds) { 00056 stop(); 00057 period_us = 00058 std::chrono::duration<size_t, std::micro>(size_t(period_seconds * 1e6)); 00059 start(); 00060 } 00061 00062 } // namespace msp