线程通信机制之定时器队列
——每周杂谈 第008篇
作者:Tocy 时间:2012-06-01
关键词:定时器队列,ITC
定时器队列(Timer Queue)可以使用CreateTimerQueue函数创建。定时器队列中的定时器是轻量级对象,可以在一定时间间隔之后调用指定的回调函数(可以只调用一次,也可以是周期性的)。这种等待操作由线程池中某个线程处理的(系统级别)。
向定时器队列中添加定时器可以使用CreateTimerQueueTimer函数。更新一个计时器队列中的计时器可以使用 ChangeTimerQueueTimer 函数。这两个函数中你可以指定一个回调函数,如果设定时间到达,线程池中某个线程会调用该回调函数。
使用 DeleteTimerQueueTimer函数可以取消挂起的计时器。当不再使计时器队列的时候,调用 DeleteTimerQueueEx 函数删除计时器队列,该函数调用是会取消并删除任何在该队列中等待的计时器。
MSDN链接:http://msdn.microsoft.com/en-us/library/ms686796(v=vs.85)
使用例子如下:
#include <windows.h>
#include <stdio.h>
HANDLE gDoneEvent;
VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired)
{
if (lpParam == NULL)
{
printf("TimerRoutine lpParam is NULL\n");
}
else
{
// lpParam points to the argument; in this case it is an int
printf("Timer routine called. Parameter is %d.\n",
*(int*)lpParam);
if(TimerOrWaitFired)
{
printf("The wait timed out.\n");
}
else
{
printf("The wait event was signaled.\n");
}
}
SetEvent(gDoneEvent);
}
int main()
{
HANDLE hTimer = NULL;
HANDLE hTimerQueue = NULL;
int arg = 123;
// Use an event object to track the TimerRoutine execution
gDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL == gDoneEvent)
{
printf("CreateEvent failed (%d)\n", GetLastError());
return 1;
}
// Create the timer queue.
hTimerQueue = CreateTimerQueue();
if (NULL == hTimerQueue)
{
printf("CreateTimerQueue failed (%d)\n", GetLastError());
return 2;
}
// Set a timer to call the timer routine in 10 seconds.
if (!CreateTimerQueueTimer( &hTimer, hTimerQueue,
(WAITORTIMERCALLBACK)TimerRoutine, &arg , 10000, 0, 0))
{
printf("CreateTimerQueueTimer failed (%d)\n", GetLastError());
return 3;
}
// TODO: Do other useful work here
printf("Call timer routine in 10 seconds...\n");
// Wait for the timer-queue thread to complete using an event
// object. The thread will signal the event at that time.
if (WaitForSingleObject(gDoneEvent, INFINITE) != WAIT_OBJECT_0)
printf("WaitForSingleObject failed (%d)\n", GetLastError());
CloseHandle(gDoneEvent);
// Delete all timers in the timer queue.
if (!DeleteTimerQueue(hTimerQueue))
printf("DeleteTimerQueue failed (%d)\n", GetLastError());
return 0;
}
这段代码比较容易理解,这里不做详细解释了。功能很简单:利用定时器队列实现延时10s执行指定回调函数。
比较有意思的是:CreateTimerQueueTimer函数。
该函数功能是创建一个计时器队列中的计时器。原型如下:
BOOL WINAPI CreateTimerQueueTimer(
__out PHANDLE phNewTimer, //计时器句柄指针
__in_opt HANDLE TimerQueue, //计时器队列句柄
__in WAITORTIMERCALLBACK Callback, //回调函数指针
__in_opt PVOID Parameter, //传给回调函数的参数
__in DWORD DueTime, //到期时间(以毫秒为单位)
__in DWORD Period, //计时器周期(以毫秒为单位)
__in ULONG Flags //标志位,通常使用0
);
计时器在DueTime时间过后首次到期,然后按照给定的period时间间隔到期,每次到期都会调用回调函数。
其参数中计时器队列指针可以为NULL(此时计时器与默认计时器队列关联)。period如果为0,计时器指signaled一次;如果大于0,计时器是周期性的,直到计时器被取消。
Windows下的计时器有三类:Timer,timer queue,和waitable timer。从复杂度上而言,一次增加,功能也更加强大。Timer只能用在单独一个计时器处理函数或者WM_TIMER消息中,而timer queue可以提供更多更准确的计时方式(在线程池中运行,效率更高), waitable timer则是同步对象,可以用于多进程之间的通信。从功能上而言基本都是一致的,只有timer提供简单的周期执行(没有单次执行的计时器,当然可以实现这种计时器的)。
所以如果需要使用timer (计时器)的话,最好从最简单的开始,如果性能不能满足要求,依次尝试timer、timer queue、waitable timer。
注:版权所有,请勿用于商业用途,转载请注明原文地址。本人保留所有权利。