windows定时器编程

目前,Windows下的定时器编程主要有三种方式。

1)SetTimer定时器是利用Windows窗口消息WM_TIMER来实现的。使用方法非常简单,SetTimer创建定时器,KillTimer销毁定时器。使用条件是调用线程必须要有窗口消息队列message queue,因此如果是工作线程就无法使用这种方法。


2)WaitableTimer定时器,其实应该算是一种线程同步对象,CreateWaitableTimer创建定时器对象,SetWaitableTimer设置定时器回调函数,CLoseHandle销毁定时器。WaitableTimer可以跨线程、进程使用,只要知道定时器对象名字(创建定时器时设置)就可以控制该定时器对象了。WaitableTimer定时器的回调函数实际上是一个APC(Asynchronous Procedure Calls)异步过程调用函数。
关于APC方面的知识可参考“谈谈对APC的一点理解”一文http://blog.csdn.net/wwwwly/archive/2009/07/10/4337907.aspx


3)TimerQueueTimer定时器,应该算迄今为止Windows系统最强大的定时器了。他可以支持多种工作模式,而且定时精度也是最高的。
使用时,首先要调用CreateTimerQueue创建一个定时器队列,然后用CreateTimerQueueTimer来创建一个TimerQueueTimer定时器,
WT_EXECUTEDEFAULT,默认设置,回调函数将进入一个非I/O工作线程队列WT_EXECUTEINTIMERTHREAD,回调函数作为APC,在定时器线程中被调用,被调用的条件是线程进入可警告等待状态alertable wait status。仅适用于短时任务,否则可能会影响队列中的其他定时器。
WT_EXECUTEINIOTHREAD,回调函数进入一个I/O工作线程队列,请注意,大多数定时器都需要调用线程进入可警告等待状态alertable wait status,并不是随随便便就能发生定时调用的。一个线程是否进入可警告等待状态可参见微软的说明http://msdn.microsoft.com/en-us/library/ms686307.aspx
A thread goes into an alertable wait state by calling either SleepEx, MsgWaitForMultipleObjectsEx, WaitForSingleObjectEx, or WaitForMultipleObjectsEx, with the function's bAlertable parameter set to TRUE.
所以希望定时器不受这种可警告等待状态的影响,最好是用TimerQueue来完成。

等待定时器与用户定时器的区别

1、等待定时器(SetWaitableTimer)与用户定时器(SetTimer)它们之间的最大差别是,用户定时器需要在应用程序中设置许多附加的用户界面结构,这使定时器变得资源更加密集。

2、等待定时器属于内核对象,这意味着它们可以供多个线程共享,并且是安全的。

用户定时器:用户定时器能够生成WM_TIMER消息,这些消息将返回给调用SetTimer(用于回调定时器)的线程和创建窗口(用于基于窗口的定时器)的线程。因此,当用户定时器报时的时候,只有一个线程得到通知。

等待定时器:多个线程可以在等待定时器上进行等待,如果定时器是个人工重置的定时器,则可以调度若干个线程。

如果要执行与用户界面相关的事件,以便对定时器作出响应,那么使用用户定时器来组织代码结构可能更加容易些,因为使用等待定时器时,线程必须既要等待各种消息,又要等待内核对象(如果要改变代码的结构,可以使用MsgaitForMultipleObjects函数)。

等待定时器,当到了规定时间的时候,更有可能得到通知。WM_TIMER消息始终属于最低优先级的消息,当线程的队列中没有其他消息时,才检索该消息。等待定时器的处理方法与其他内核对象没有什么差别(PS:因此其使用与内核对象的使用一个样,这就是所谓的触类旁通吧),如果定时器发出报时信息,而你的线程正在等待之中,那么你的线程就会醒来。

一个windows编程示例

#include <iostream>
#include <windows.h> 
#include <stdio.h>

using namespace std;

static  int COUNT = 0;

VOID CALLBACK TimerRoutine(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{
    if (NULL == lpParameter)
    {
        cout << "TimerRoutine parameter is NULL!" << endl;
        return;
    }

    printf("the values of param is :%d\n", *(int*)lpParameter);
}

int main(int argc, TCHAR *argv[])
{
    HANDLE m_hTimerQueueTimer = NULL;
    HANDLE m_hTimerQueue = NULL;

    while (NULL == (m_hTimerQueue = CreateTimerQueue())) {
        cout << "Create timer queue failed!" << endl;
        Sleep(10);
    }

    while (!CreateTimerQueueTimer(&m_hTimerQueueTimer, m_hTimerQueue, WAITORTIMERCALLBACK(TimerRoutine), &COUNT, 1000, 1000, NULL))
    {
        cout << "Create timer failed!" << endl;
        Sleep(10);
    }

    while (1) {
        Sleep(1000);
        COUNT++;
    }

    if (m_hTimerQueueTimer != NULL)
        DeleteTimerQueueTimer(m_hTimerQueue, m_hTimerQueueTimer, INVALID_HANDLE_VALUE);
    if (m_hTimerQueue != NULL)
        DeleteTimerQueueEx(m_hTimerQueue, INVALID_HANDLE_VALUE);

    m_hTimerQueueTimer = NULL;
    m_hTimerQueue = NULL;


    return 0;
}

 

参考:

1.  Windows系统三种定时器的分析

2. CreateTimerQueueTimer学习笔记 

3. Sleep和 SleepEx函数

posted @ 2019-12-10 19:42  yuxi_o  阅读(1926)  评论(0编辑  收藏  举报