I wrote this class today, but I am trying to figure out how to make it more accurate. I pass in seconds and multiply by 1000 to make it milliseconds, and the time does not line up. I need the ability to have multiple timers, so using `timer_gettime()`, which limits one clock per process, is not an option. Also note I borrowed my idea from free glut. Please feel free to leave general comments on style, but please focus more on how to improve the accuracy of the timer. #include "TimerManager.h" #include <iostream> void func1(int id) { std::cout << "I was called with " << std::endl; } void func2(int id) { std::cout << "I was called too ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))" << std::endl; } int main(int argc, char *argv[]) { TimerManager t; t.addTimer(6, func1); t.addTimer(2, func2); while(true) { t.start(); } return 0; } --- #ifndef TIMERMANAGER_H_ #define TIMERMANAGER_H_ #include <stdlib.h> #include <iostream> #include <pthread.h> #include <list> extern "C" { void *create_pthread(void *data); } class TimerManager { public: TimerManager(); ~TimerManager(); void start(); void stop(); void addTimer(long usec, void (*callback)(int id)); private: class Timer { public: Timer(long usec, void (*callback)(int)) : duration(usec), callback(callback), start(0) { } bool operator ==(Timer other) { if ((this->callback == other.callback) && (this->duration == other.duration)) { return true; } return false; } long duration; void (*callback)(int); long start; }; std::list<Timer> m_timers; pthread_t m_timer_thread; Timer setUpTimer(long usec, void (*callback)(int id)); friend void *create_pthread(void *data); void run(); bool go; }; #endif --- #include <algorithm> #include <iterator> #include <sys/time.h> #include "TimerManager.h" extern "C" void *create_pthread(void *data) { TimerManager *thread_timer_manager = static_cast<TimerManager *>(data); thread_timer_manager->run(); return data; } TimerManager::TimerManager() : go(false) { int thread_creation = pthread_create(&m_timer_thread, NULL, create_pthread, this); if(thread_creation != 0) { std::cerr << "Failed to create thread" << std::endl; return; } else { std::cout << "The status flag is " << thread_creation << std::endl; } } TimerManager::~TimerManager() { } void TimerManager::run() { struct timeval l_tv; while(true) { if (go) { typedef std::list<Timer>::iterator li; li begin = m_timers.begin(); li end = m_timers.end(); int item = 0; for(;begin != end; ++begin) { gettimeofday(&l_tv, NULL); long elapsed_time = (l_tv.tv_usec - begin->start); sleep(1); if (elapsed_time >= begin->duration) { //std::cout << "Status of timer " << item << " is " << elapsed_time << " > " << begin->duration << std::endl; begin->callback(item); gettimeofday(&l_tv, NULL); begin->start = l_tv.tv_usec; } else { //std::cout << "Status of timer " << item << " is " << elapsed_time << " < " << begin->duration << std::endl; } item++; } } } } void TimerManager::start() { go = true; } oid TimerManager::stop() { go = false; } TimerManager::Timer TimerManager::setUpTimer(long usec, void (*callback)(int id)) { struct timeval l_tv; gettimeofday(&l_tv, NULL); Timer l_t(usec * 100, callback); l_t.start = l_tv.tv_usec; std::cout << "Timer created with a values of START: " << l_t.start << " CALLBACK: " << &l_t.callback << " DURATION: " << l_t.duration << std::endl; return l_t; } void TimerManager::addTimer(long usec, void (*callback)(int id)) { Timer insert = setUpTimer(usec, callback); typedef std::list<Timer>::iterator li; li begin = m_timers.begin(); li end = m_timers.end(); for(;begin != end; ++begin) { if (*begin == *end) { return; } } m_timers.push_back(insert); } ---------------- #*Update*: Changes after reading answers. Here is the updated code, #include "TimerManager.h" #include <iostream> #include <fstream> #include <sys/time.h> extern "C" void func1(int id) { struct timeval l_tv; gettimeofday(&l_tv, NULL); std::cout << "I was called (1) @ " << l_tv.tv_usec << std::endl; } extern "C" void func2(int id) { struct timeval l_tv; gettimeofday(&l_tv, NULL); std::cout << "I was called (2) @ " << l_tv.tv_usec << std::endl; } int main(int, char *[]) { TimerManager t; t.addTimer(1000000 / 2, func1); t.addTimer(1000000 * 4, func2); t.start(); while(true) { sleep(1); } return 0; } --- #ifndef TIMERMANAGER_H_ #define TIMERMANAGER_H_ #include <stdlib.h> #include <iostream> #include <pthread.h> #include <list> extern "C" { void *create_pthread(void *data); } class TimerManager { public: TimerManager(); ~TimerManager(); void start(); void stop(); void addTimer(long usec, void (*callback)(int id)); private: class Timer { public: Timer(long usec, void (*callback)(int)) : duration(usec), callback(callback), start(0) { } bool operator ==(Timer other) { if ((this->callback == other.callback) && (this->duration == other.duration)) { return true; } return false; } void operator =(Timer other) { duration = other.duration; callback = other.callback; start = other.start; } suseconds_t duration; void (*callback)(int); suseconds_t start; }; Timer setUpTimer(long micro_duration, void (*callback)(int id)); friend void *create_pthread(void *data); void run(); bool m_bRunning; bool m_bGo; long m_lMinSleep; std::list<Timer> m_cTimers; pthread_t m_tTimerThread; pthread_cond_t m_tGoLockCondition; pthread_mutex_t m_tGoLock; }; #endif --- #include <algorithm> #include <iterator> #include <sys/time.h> #include "TimerManager.h" extern "C" void *create_pthread(void *data) { TimerManager *thread_timer_manager = static_cast<TimerManager *>(data); thread_timer_manager->run(); return data; } TimerManager::TimerManager() : m_bRunning(false), m_bGo(false), m_lMinSleep(0) { int mutex_creation = pthread_mutex_init(&m_tGoLock, NULL); if(mutex_creation != 0) { std::cerr << "Failed to create mutex" << std::endl; // Use RAII if resource acquisition fails return; } int mutex_cond_creation = pthread_cond_init(&m_tGoLockCondition, NULL); if(mutex_cond_creation != 0) { std::cerr << "Failed to create condition mutex" << std::endl; // Use RAII if resource acquisition fails return; } int thread_creation = pthread_create(&m_tTimerThread, NULL, create_pthread, this); // On success call create_pthread to start tiemr loop if(thread_creation != 0) { std::cerr << "Failed to create thread" << std::endl; // Use RAII if resource acquisition fails return; } m_bRunning = true; } TimerManager::~TimerManager() { pthread_mutex_lock(&m_tGoLock); // m_bRunning access on other thread m_bRunning = false; pthread_mutex_unlock(&m_tGoLock); void *result; pthread_join(m_tTimerThread, &result); // Do not let calling thread exit before deleting pthread_mutex_destroy(&m_tGoLock); // Now destroy the mutex (release resources) pthread_cond_destroy(&m_tGoLockCondition); } void TimerManager::run() { pthread_mutex_lock(&m_tGoLock); // Timers run on seperate thread while(m_bRunning) { // While timer manager exists while (!m_bGo) { // While timer manager told to run pthread_cond_wait(&m_tGoLockCondition, &m_tGoLock); // Set in the start() member function } pthread_mutex_unlock(&m_tGoLock); // Once timer unlocked and mutex released if (!m_bRunning) { // Make sure timer manager not out of scope break; } struct timeval l_tv; usleep(std::max(0l, m_lMinSleep)); gettimeofday(&l_tv, NULL); // System call to get time of day m_lMinSleep = 0; // Used to sleep if no timer to go off soon long l_lMin = 0; // Used if timer goes off to get actual Min sleep for(std::list<Timer>::iterator it = m_cTimers.begin(); it != m_cTimers.end(); ++it) { // Iterate over timers to see which one is going off TimerManager::Timer l_oTimer = *it; // Obtain a copy of the timer long elapsed_time = ((l_tv.tv_sec * 1000000 + l_tv.tv_usec) - (l_oTimer.start)); // Calcuate the elapsed time from the start of timer X l_lMin = elapsed_time - l_oTimer.duration; // Minimum time you can sleep in loop if (elapsed_time >= l_oTimer.duration) { // If time passed is greater than or equal to duration: THEN l_lMin = l_oTimer.duration; // The minimum you can wait is possibly the entire duration of that timer l_oTimer.callback(0); // Call the call back gettimeofday(&l_tv, NULL); // After callback called... it->start = (l_tv.tv_sec * 1000000) + l_tv.tv_usec; // Start the timer over again } m_lMinSleep = std::min(m_lMinSleep, l_lMin); // Find the actual minumum time you can sleep to not lock } } } void TimerManager::start() { pthread_mutex_lock(&m_tGoLock); // Go flag accessed from another thread m_bGo = true; pthread_cond_signal(&m_tGoLockCondition); pthread_mutex_unlock(&m_tGoLock); } void TimerManager::stop() { pthread_mutex_lock(&m_tGoLock); // Go flag accessed from another thread m_bGo = false; pthread_mutex_unlock(&m_tGoLock); } TimerManager::Timer TimerManager::setUpTimer(long micro_duration, void (*callback)(int id)) { struct timeval l_tv; gettimeofday(&l_tv, NULL); // System call to get the ms and sec since Epoch0 Timer l_oTimer(micro_duration, callback); // Create a timer l_oTimer.start = (l_tv.tv_sec * 1000000) + l_tv.tv_usec; // Tell the timer when to start return l_oTimer; // Return a copy to addTimer } void TimerManager::addTimer(long usec, void (*callback)(int id)) { pthread_mutex_lock(&m_tGoLock); // Tell object to wait till timer inserted Timer insert = setUpTimer(usec, callback); for (std::list<Timer>::iterator it = m_cTimers.begin(); it != m_cTimers.end(); ++it) { if (*it == insert) { // Return if timer callback and duration the same return; } } m_cTimers.push_back(insert); // If no duplicate timers found then insert into list pthread_mutex_unlock(&m_tGoLock); // Tell object it is okay to proceed }