等待定时器 是在某个时间或按规定的间隔时间发出自己的信号通知的内核对象。它们通常用来在某个时间执行某个操作。
创建等待定时器
HANDLE CreateWaitableTimer (
PSECURITY_ATTRIBUTES psa,
BOOL fManualReset,
PCTSTR pszName
);
psa 和 pszName 这两个参数(见内核对象的安全性 和 跨越进程边界共享内核对象【命名对象】 )
fManualReset 参数 用于指明人工重置的定时器或自动重置的定时器。(与事件的情况一样。见【内核对象线程同步】事件内核对象 )
人工重置 的定时器信号通知时,等待该定时器的所有 线程均变为可调度线程。
自动重置 的定时器信号通知时,只有一个等待 的线程变为可调度线程。
进程可以获得它自己的与进程相关的现有等待定时器的句柄,方法是调用 OpenWaitableTimer 函数: (见:跨越进程边界共享内核对象【命名对象】 :: 按名字共享对象的另一种方法)
HANDLE OpenWaitableTimer (
DWORD dwDesiredAccess,
BOOL bInheritHandle,
PCTSTR pszName
);
等待定时器对象总是在未通知状态中创建 ( 不像事件对象那样,可以让我们指定 ) 。
SetWaitableTimer 函数告诉定时器你想在何时让它成为已通知状态
BOOL SetWaitableTimer (
HANDLE hTimer,
const LARGE_INTEGER *pDueTime,
LONG lPeriod,
PTIMERAPCROUTINE pfnCompletionRoutine,
PVOID pvArgToCompletionRoutine,
BOOL fResume
);
hTimer 参数 用于指明你要设置的定时器。
pDueTime 和 lPeriod 两个参数是一道使用的。 PDueTimer 参数 用于指明定时器何时应该第一次报时,而 lPeriod 参数 则用于指明此后定时器应该间隔多长时间报时一次。
例子
下面的代码用于将定时器的第一次报时的时间设置在 2002 年 1 月 1 日的下午 1 点钟,然后每隔 6 小时报时一次:
// Declare our local variables.
HANDLE hTimer;
SYSTEMTIME st;
FILETIME ftLocal, ftUTC;
LARGE_INTEGER liUTC;
// Create an auto-reset timer.
hTimer = CreateWaitableTimer (NULL, FALSE, NULL);
// First signaling is at January 1, 2002, at 1:00 P.M. (local time).
st.wYear = 2002; // Year
st.wMonth = 1; // January
st.wDayOfWeek = 0; // Ignored
st.wDay = 1; // The first of the month
st.wHour = 13; // 1PM
st.wMinute = 0; // 0 minutes into the hour
st.wSecond = 0; // 0 seconds into the minute
st.wMilliseconds = 0; // 0 milliseconds into the second
SystemTimeToFileTime (&st, &ftLocal);
// Convert local time to UTC time.
LocalFileTimeToFileTime (&ftLocal, &ftUTC);
// Convert FILETIME to LARGE_INTEGER because of different alignment.
liUTC.LowPart = ftUTC.dwLowDateTime;
liUTC.HighPart = ftUTC.dwHighDateTime;
// Set the timer.
SetWaitableTimer (hTimer, &liUTC, 6 * 60 * 60 * 1000, NULL, NULL, FALSE);
...
代码首先对 SYSTEMTIME 结构进行初始化,该结构用于指明定时器何时第一次报时(发出信号通知)。将该时间设置为本地时间,即计算机所在时区的正确时间。 SetWaitableTimer 的第二个参数的原型是个常量 LARGE_INTEGER * ,因此它不能直接接受 SYSTEMTIME 结构。但是, FILETIME 结构和 LARGE_INTEGER 结构 拥有相同的二进制格式,都包含两个 32 位的值。因此,我们可以将 SYSTETIME 结构转换成 FILETIME 结构。再一个问题是, SetWaitableTimer 希望传递给它的时间始终都采用世界协调时( UTC )的时间。调用 LocalFileTimeToFileTime 函数,就可以很容易地进行时间的转换。
现在,若要使定时器在 2002 年 1 月 1 日下午 1 点之后每隔 6 h 进行一次报时,我们应该将注意力转向 lPeriod 参数。该参数用于指明定时器在初次报时后每隔多长时间(以毫秒为单位 )进行一次报时。如果是每隔 6h 进行一次报时,那么我传递 21600000 ( 6 h× 每小时 60min× 每分钟 60s× 每秒 1000 ms )。另外,如果给它传递了以前的一个绝对时间,比如 1 9 7 5 年 1 月 1 日下午 1 点,那么 SetWaitableTimer 的运行就不会失败。
让定时器在一个相对于调用 SetWaitableTimer 的时间进行报时 代码下载
只需要在 pDueTime 参数中传递一个负值 。传递的值必须是以 100ns 为间隔。 由于我们通常并不以 100ns 的间隔来思考问题,因此我们要说明一下 100ns 的具体概念: 1s = 1000ms = 1000000µs = 100 000000ns 。
g_hTimer = CreateWaitableTimer(NULL, FALSE, NULL);
const int nTimerUnitsPerSecond = 10000000 ;
LARGE_INTEGER li;
li.QuadPart = - ( 3 * nTimerUnitsPerSecond);
SetWaitableTimer(g_hTimer, & li, 1000 , NULL, NULL, FALSE);
通常情况下,你可能想要一个一次报时的定时器 ,它只是发出一次报时信号,此后再也不发出报时信号。若要做到这一点,只需要为 lPeriod 参数传递 0 即可 。然后可以调用 CloseHandle 函数,关闭定时器 ,或者再次调用 SetWaitableTimer 函数,重新设置时间,为它规定一个需要遵循的新条件。
参数是 fResume ,它可以用于支持暂停和恢复 的计算机。通常可以为该参数传递 FALSE ,就像我在上面这个代码段中设置的那样。但是,如果你编写了一个会议安排类型的应用程序,在这个应用程序在中,你想设置一个为用户提醒会议时间安排的定时器,那么应该传递 TRUE 。 当定时器报时的时候,它将使计算机摆脱暂停方式(如果它处于暂停状态的话),并唤醒等待定时器报时的线程。然后该应用程序运行一个波形文件,并显示一个消息框,告诉用户即将举行的会议。如果为 fResume 参数传递 FALSE , 定时器对象就变为已通知状态,但是它唤醒的线程必须等到计算机恢复运行(通常由用户将它唤醒)之后才能得到 CPU 时间。 ( 还不是很明白 , 暂停计算机是什么意思,进入睡眠吗? )
BOOL CancelWaitableTimer (HANDLE hTimer);
这个简单的函数用于取出定时器的句柄并将它撤消,这样,除非接着调用 SetWaitableTi mer 数以便重新设置定时器,否则定时器决不会进行报时。如果想要改变定时器的报时条件, 不必在调用 SetWaitableTimer 函数之前调用 CancelWaitableTimer 函数。每次调用 SetWaitableTier 函数,都会在设置新的报时条件之前撤消定时器原来的报时条件。
本文地址:http://www.cnblogs.com/fangyukuan/archive/2010/09/05/1818293.html