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;
}
运行结果为: