Welcome

首页 / 软件开发 / C++ / 通过异步程序调用(APC)实现的定时功能

通过异步程序调用(APC)实现的定时功能2011-04-25张海粟定时器是一个在特定时间或者规则间隔被激发的内核对象。结合定时器的异步程序调用可 以允许回调函数在任何定时器被激发的时候执行。本文的例子代码显示了如何实现。

使用本定时器时,你需要把常量_WIN32_WINNT定义为0x0400,并且此常量应该在包之前定义 ,以确保声明合适的定时器原型函数。

通过调用CreateWaitableTimer()可以创建一 个定时器,此函数返回一个指向内核对象的句柄。若定时器已经存在,你可以通过使用 OpenWaitableTimer()获得一个进程相关的句柄。无论是通过CreateWaitableTimer() 还是通 过OpenWaitableTimer()获得的句柄,在不需要定 时器时必须释放,方法是使用函数 CloseHandle()。

定时的时间通过调用SetWaitableTimer()来设置,可以设置为一个 特定的时刻(如December 16, 1999 at 9:45 PM)或者一个相对的时间(如从现在起每五分 钟)。函数SetWaitableTime()定时的时间参数要求LARGE_INTEGER类型。这个值应该符合在 结构体FILETIME中描述的格式。如果值是正的,代表一个特定的时刻。如果值是负的,代表 以100纳秒为单位的相对时间。后面的示例代码中使用的是相对时间。在调用 SetWaitableTimer()函数后,定时器将在每5秒被激发一次。

你也可以将定时器设置 为周期性的自我激发,方法是向SetWaitableTimer()的第三个参数传递一个周期参数(以毫 秒为单位)。在CreateWaitableTimer()的第二个参数传递FALSE可以产生一个自动归零的定 时器。本例设置周期为两秒的定时器。

当设置了定时器之后,你就可以将APC与其结 合起来。这里把APC函数称作完全例程。完全例程的地址作为SetWaitableTimer()的第四个参 数。第五个参数是一个空类型的指针,你可以使用它来传递完全例程的参数。

在所有 的APC中,要执行一个完全例程则线程必须处于监听状态。完全例程将总是被调用 SetWaitableTimer()的相同的线程执行,所以此线程必须将必须其自身置于监听状态。可以 调用下面的任何一个监听函数来完成监听状态的设置:

SleepEx();

WaitForSingleObjectEx();

WaitForMultipleObjectsEx();

MsgWaitForMultipleObjectsEx();

SignalObjectAndWait();

任何一个线程都有一个APC队列。在调用上面的任何一个函数时,如果线程的APC队列中有 实体,则此线程不会进入休眠状态,取而代之要做的是将实体从APC队列中取出,然后调用相 应的完全例程。

如果在APC队列中不存在实体,那么线程将会被挂起,直至等待条件 满足为止。满足等待条件的有:一个实体加入到APC队列中,超时,激活句柄等,以及在调用 MsgWaitForMultipleObjectsEx()情况下,一个消息进入到线程的一个消息队列中。若等待条 件满足的是APC队列中的一个实体,那么线程会被激活,并且执行完全例程,这种情况下的函 数的返回值是 WAIT_IO_COMPLETION.

【重要提示】

1、在执行完一个完全例程 之后,系统会检查在APC中剩下的实体以处理。一个监视函数仅仅在处理完所有APC实体后才 返回。因此,如果实体加入到APC队列的速度比处理的更快的话,则调用这些函数可能永远也 不能返回。特别当定时等待的时间比起要求执行完全例程的时间更短的话,这种情况更容易 发生。