Windows提供了可等待的計時器內核對象,它使我們非常容易的得到一個基於時間的通知。創建一個可等待計時器內核對象會浪費系統資源。利用線程池來處理定時任務再合適不過了。
PTP_TIMER CreateThreadpoolTimer(
PTP_TIMER_CALLBACK pfnTimerCallback,
PVOID pvContext,
PTP_CALLBACK_ENVIRON pcbe);
與創建工作項函數CreateThreadpoolWork相似。pfnTimerCaizhllback必須是以下函數的原型。
VOID CALLBACK TimeoutCallback(
PTP_CALLBACK_INSTANCE pInstance,
PVOID pvContext,
PTP_TIMER pTimer);
pvContext是pfnTimerCallback的參數,可以爲NULL,pTimer參數中傳入一個計時器對象的指針,該計時器對象由CreateThreadpoolTimer函數創建並返回。
當我們想向線程池註冊計時器的時候,需調用SetThreadpoolTimer函數:
VOID SetThreadpoolTimer(
PTP_TIMER pTime,
PFILETIME pftDueTime,
DWORD msPeriod,
DWORD msWindowLength);
pTime標識CreateThreadpoolTimer返回的PTP_TIMER對象,pftDueTime表示第一次調用回調函數應該是什麼時候,傳一個負數來指定一個相對時間,但-1是一個特例,用來表示立即開始。爲了指定一個絕對時間,應該傳正值,這個值以100納秒爲單位,從1600年1月1日開始計算。
如果只想讓定時器只觸發一次,那麼msPeriod參數傳入0即可。msWindowsLength傳入一個正數,增加隨機性。
WaitForThreadpoolTimerCallbacks和CloseThreadpoolTimer分別用來等待計時器完成和釋放計時器的內存。
下面是代碼demo:
//定時器
TCHAR g_szCaption[100];
int g_nSecLeft = 0;
VOID CALLBACK TimeoutCallback(
PTP_CALLBACK_INSTANCE pInstance,
PVOID pvContext,
PTP_TIMER pTimer)
{
TCHAR szMsg[100];
StringCchPrintf( szMsg, _countof(szMsg), _T("You have %d seconds to respond\n"), --g_nSecLeft);
_tprintf(_T("szMsg=%s\n"), szMsg );
}
//end
int _tmain( int argc, TCHAR* argv[] )
{
//定時器
g_nSecLeft = 10;
PTP_TIMER pTimer = CreateThreadpoolTimer(TimeoutCallback, NULL, NULL);
if (NULL == pTimer)
{
_tprintf(_T("Impossible to create the timer:%u\n"), GetLastError());
return -1;
}
ULARGE_INTEGER ulRelativeStartTime;
ulRelativeStartTime.QuadPart = (LONGLONG)-(10000000);
FILETIME ftRelativeStartTime;
ftRelativeStartTime.dwHighDateTime = ulRelativeStartTime.HighPart;
ftRelativeStartTime.dwLowDateTime = ulRelativeStartTime.LowPart;
SetThreadpoolTimer(pTimer, &ftRelativeStartTime, 1000, 0);
_tprintf(_T("You have 10 seconds to respond\n"));
while ( g_nSecLeft > 0)
{
;
}
WaitForThreadpoolTimerCallbacks(pTimer, FALSE);
CloseThreadpoolTimer(pTimer);
return 0;
}
運行結果爲: