Simple C++ Timer Wrapper
Introduction
There are a wide variety of Windows timers available, this along with their different methods of implementation can make the task of including a simple timer into a piece of source code rather confusing, especially for someone new to C++. TemplateTimer does noting special but does offer a convenient wrapper for the programmer who needs to implement a simple timer within a C++ class.
Code Discussion
In this implementation CreateTimerQueueTimer() has been used as the timer but there are different timers available. CreateTimerQueueTimer() has been implemented using WT_EXECUTEINTIMERTHREAD (for short tasks) but may be changed to suit specific requirements. It should be noted that this timer (as with all Windows timers) suffers from inherent non real time OS in-accuracies. The performance is system dependent however after testing the timer resolution was accurate around and above a 200ms interval.
The Start() method has two overloads. The default method simply allows the timer to be started with an interval in milliseconds. The first overload allows the timer to be started immediately (i.e. the first timed event is called immediately). The second overload allows the timer to be called only once.
The templated class TTimer implements a callback using templates. This allows the specification of a class function as the callback function through SetTimedEvent().
CTimer implements a virtual method OnTimedEvent() that is called by the timer procedure TimerProc(). TTimer derives from CTimer and overrides the OnTimerEvent() method which in tern calls the (user defined) callback function.
GetCount() and SetCount() use InterlockedExchangeAdd() and InterlockedExchange() to provide a thread safe timer event count that can be read (or set) anywhere in the code. This use of InterlockedExchange() provides a convenient way of providing very quick mutex access to a number.
The Stop() method is used to stop the timer. If required it can be used within the OnTimedEvent() function, for example to stop timer1 after 10 times (10 sec) use: if( timer1.GetCount() == 10 ){ timer1.Stop(); }
Using the Code
For convenience the TTimer and CTimer classes have been implemented in a single file (TemplateTimer.h). To use TemplateTimer simply include TemplateTimer.h into your project and implement as shown in the test code TimerTest.cpp/.h
'TemplateTimer.h' (See the 'Download source' link above)
#pragma once #include <atlbase.h> static void CALLBACK TimerProc(void*, BOOLEAN); /////////////////////////////////////////////////////////////////////////////// // // class CTimer // class CTimer { public: CTimer() { m_hTimer = NULL; m_mutexCount = 0; } virtual ~CTimer() { Stop(); } bool Start(unsigned int interval, // interval in ms bool immediately = false,// true to call first event immediately bool once = false) // true to call timed event only once { if( m_hTimer ) { return false; } SetCount(0); BOOL success = CreateTimerQueueTimer( &m_hTimer, NULL, TimerProc, this, immediately ? 0 : interval, once ? 0 : interval, WT_EXECUTEINTIMERTHREAD); return( success != 0 ); } void Stop() { DeleteTimerQueueTimer( NULL, m_hTimer, NULL ); m_hTimer = NULL ; } virtual void OnTimedEvent() { // Override in derived class } void SetCount(int value) { InterlockedExchange( &m_mutexCount, value ); } int GetCount() { return InterlockedExchangeAdd( &m_mutexCount, 0 ); } private: HANDLE m_hTimer; long m_mutexCount; }; /////////////////////////////////////////////////////////////////////////////// // // TimerProc // void CALLBACK TimerProc(void* param, BOOLEAN timerCalled) { CTimer* timer = static_cast<CTimer*>(param); timer->SetCount( timer->GetCount()+1 ); timer->OnTimedEvent(); }; /////////////////////////////////////////////////////////////////////////////// // // template class TTimer // template <class T> class TTimer : public CTimer { public: typedef private void (T::*TimedFunction)(void); TTimer() { m_pTimedFunction = NULL; m_pClass = NULL; } void SetTimedEvent(T *pClass, TimedFunction pFunc) { m_pClass = pClass; m_pTimedFunction = pFunc; } protected: void OnTimedEvent() { if (m_pTimedFunction && m_pClass) { (m_pClass->*m_pTimedFunction)(); } } private: T *m_pClass; TimedFunction m_pTimedFunction; };
Test Example (see the 'Download Demo Project' link above)
'TimerTest.h'#pragma once #include "TemplateTimer.h" class CTimerTest { public: void RunTest(); private: void OnTimedEvent1(); void OnTimedEvent2(); TTimer<CTimerTest> timer1 ; TTimer<CTimerTest> timer2 ; };
'TimerTest.cpp'
#include "stdafx.h" #include "TimerTest.h" void CTimerTest::OnTimedEvent1() { printf("\r\nTimer 1 Called (count=%i)", timer1.GetCount()); } void CTimerTest::OnTimedEvent2() { printf("\r\nTimer 2 Called (count=%i)", timer2.GetCount()); } void CTimerTest::RunTest() { printf("Hit return to start and stop timers"); getchar(); timer1.SetTimedEvent(this, &CTimerTest::OnTimedEvent1); timer1.Start(1000); // Start timer 1 every 1s timer2.SetTimedEvent(this, &CTimerTest::OnTimedEvent2); timer2.Start(2000); // Start timer 2 every 2s // Do something, in this case just wait for user to hit return getchar(); // Wait for return (stop) timer1.Stop(); // Stop timer 1 timer2.Stop(); // Stop timer 2 printf("\r\nTimers stopped (hit return to exit)"); getchar(); }
Example Output
发表评论
BgjpB2 You have made some good points there. I looked on the net for additional information about the issue and found most individuals will go along with your views on this web site.
DnyjBP Right now it appears like Drupal is the best blogging platform available right now. (from what I ave read) Is that what you are using on your blog?
9O56R8 post and a all round exciting blog (I also love the theme/design), I don at have time to look
3aNr1v Im obliged for the blog.
JtkwAU Thanks a lot for the blog post.Much thanks again. Awesome.