平时创建定时器使用的是WINAPI SetTimer,不过该函数一般用于有界面的时候。无界面的情况下,可以选择微软提供的CreateWaitableTimer和SetWaitableTimer API。
HANDLE WINAPI CreateWaitableTimer( _In_opt_ LPSECURITY_ATTRIBUTES lpTimerAttributes, _In_ BOOL bManualReset, _In_opt_ LPCTSTR lpTimerName ); BOOL WINAPI SetWaitableTimer( _In_ HANDLE hTimer, _In_ const LARGE_INTEGER *pDueTime, _In_ LONG lPeriod, _In_opt_ PTIMERAPCROUTINE pfnCompletionRoutine, _In_opt_ LPVOID lpArgToCompletionRoutine, _In_ BOOL fResume );
详细介绍可以查看MSDN( http://msdn.microsoft.com/en-us/library/windows/desktop/ms682492(v=vs.85).aspx )
我自己在使用的时候,封装了一个类,用来创建了一个线程,并定时调用我提供的函数。类代码如下:
1 #ifndef APLAYER_TIMERTHREAD_H 2 #define APLAYER_TIMERTHREAD_H 3 #include <Windows.h> 4 class CTimerThread 5 { 6 public: 7 CTimerThread() : 8 _hThread(NULL), _hEvent(NULL), 9 _bRunning(false), _nInterval(10) 10 {} 11 ~CTimerThread() 12 { 13 KillTimer(); 14 } 15 public: 16 int CreateTimer(unsigned int interval, PTIMERAPCROUTINE func, void* lpParam); 17 void KillTimer(); 18 private: 19 static DWORD WINAPI timerThread(LPVOID lpParam); 20 21 private: 22 HANDLE _hTimer; 23 int _nInterval; 24 HANDLE _hEvent; 25 void* _lpParam; 26 27 PTIMERAPCROUTINE _callbackFunc; 28 HANDLE _hThread; 29 DWORD _dwThread; 30 bool _bRunning; 31 }; 32 33 #endif
1 #include "TimerThread.h" 2 3 void CTimerThread::KillTimer() 4 { 5 if (_hTimer != NULL) { 6 CancelWaitableTimer(_hTimer); 7 CloseHandle(_hTimer); 8 _hTimer = NULL; 9 } 10 _bRunning = false; 11 } 12 int CTimerThread::CreateTimer(unsigned int interval, PTIMERAPCROUTINE func, void* lpParam) 13 { 14 if (_bRunning) return TRUE; 15 _nInterval = interval; 16 _callbackFunc = func; 17 _lpParam = lpParam; 18 _bRunning = true; 19 _hThread = CreateThread( 20 NULL, 21 0, 22 timerThread, 23 this, 24 0, 25 &_dwThread 26 ); 27 if (_hThread == NULL) { 28 _bRunning = false; 29 return FALSE; 30 } 31 CloseHandle(_hThread); 32 return TRUE; 33 } 34 35 DWORD CTimerThread::timerThread(LPVOID lpParam) 36 { 37 CTimerThread* pThis = (CTimerThread*)lpParam; 38 do { 39 pThis->_hTimer = CreateWaitableTimer(NULL, FALSE, NULL); 40 if (pThis->_hTimer == NULL) break; 41 42 LARGE_INTEGER liDueTime; 43 liDueTime.QuadPart = 0; 44 BOOL bRet = SetWaitableTimer( 45 pThis->_hTimer, 46 &liDueTime, 47 pThis->_nInterval, 48 pThis->_callbackFunc, 49 pThis->_lpParam, 50 FALSE); 51 do { 52 SleepEx(30000, TRUE); 53 } while (pThis->_bRunning); 54 return bRet; 55 } while (0); 56 return 0; 57 }
TimerThread.h/cpp实现了一个可以定时调用函数的类。使用的时候也很简单。首先定义一个要被调用的函数
void __stdcall DoSomething(void *lpParam, DWORD, DWORD)
{
//to do
}
void *lpParam;
CTimerThread _timer;
_timer.CreateTimer(50, DoSomething, lpParam);
//
some code
....
//
_timer.KillTimer();
DoSomething函数在_timer.CreateTimer 和_timer.KillTimer之间会每隔50ms调用一次。
下面根据我自己的理解介绍下这两个函数。
1 HANDLE WINAPI CreateWaitableTimer( 2 _In_opt_ LPSECURITY_ATTRIBUTES lpTimerAttributes, 3 _In_ BOOL bManualReset, 4 _In_opt_ LPCTSTR lpTimerName 5 );
用来创建一个timer对象。首先翻译下MSDN对各参数的介绍(个人理解):
lpTimerAttributes
略过,具体可以查看MSDN或《Windows核心编程》,一般设置为NULL。
bManualReset
If this parameter is TRUE, the timer is a manual-reset notification timer. Otherwise, the timer is a synchronization timer.
(此处不知道如何翻译才能清晰的传达意思,故抄录原文。用我的语言解释就是,如果为TRUE,则该timer到时间时,需要手动重置才能有下一次;FALSE则每次到时后自动进行下一次计时)
lpTimerName
该timer对象的名称。最大MAX_PATH个字母,区分大小写。
传递NULL则创建一个没有名字的timer对象。
如果名称和现有的event,semaphore,mutex,job or file-mapping对象名称冲突,则该函数失败,调用GetLastError会返回ERROR_INVALID_HANDLE错误。原因是这些对象共享相同的命名空间。
返回值(return value)
如果函数调用成功,则返回指向timer对象的handle。如果和现有的已命名timer同名,则返回指向该timer的handle。
1 BOOL WINAPI SetWaitableTimer( 2 _In_ HANDLE hTimer, 3 _In_ const LARGE_INTEGER *pDueTime, 4 _In_ LONG lPeriod, 5 _In_opt_ PTIMERAPCROUTINE pfnCompletionRoutine, 6 _In_opt_ LPVOID lpArgToCompletionRoutine, 7 _In_ BOOL fResume 8 );
启动timer对象。首先翻译下MSDN对各参数的介绍(个人理解):
hTimer
指向timer对象的handle。显然可以是CreateWaitableTimer函数返回的handle。
pDueTime
该时间之后的timer会signaled(意会下..),间隔为100纳秒(应该就是此值的单位吧?)
正值的话,就是基于UTC的绝对时间。负值的话就是相对现在的时间了。
例如-10 000 000表示1s后。
lPeriod
嗯,这个就是我比较关心的参数,signaled间隔。类似于SetTimer里那个间隔。单位毫秒(ms)
为0则只signaled一次。
pfnCompletionRoutine
每次signaled都会调用此处的函数了,传递一个函数指针。原型为:
typedef VOID (APIENTRY *PTIMERAPCROUTINE)( _In_opt_ LPVOID lpArgToCompletionRoutine, \\SetWaitableTimer传入的参数lpArgToCompletionRoutine _In_ DWORD dwTimerLowValue, _In_ DWORD dwTimerHighValue );
lpArgToCompletionRoutine
传入的参数,往上看:-)
fResume
懒得介绍,自己看msdn,一般设置为FALSE。
返回值(return value)
成功返回非零值。