线程通信机制之定时器队列

线程通信机制之定时器队列

——每周杂谈 第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。

 

注:版权所有,请勿用于商业用途,转载请注明原文地址。本人保留所有权利。

posted @ 2012-06-03 10:12  Tocy  阅读(1956)  评论(0编辑  收藏  举报