目前,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 = ; 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();
} while (!CreateTimerQueueTimer(&m_hTimerQueueTimer, m_hTimerQueue, WAITORTIMERCALLBACK(TimerRoutine), &COUNT, , , NULL))
{
cout << "Create timer failed!" << endl;
Sleep();
} while () {
Sleep();
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 ;
}

参考:

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

2. CreateTimerQueueTimer学习笔记

3. Sleep和 SleepEx函数

windows定时器编程的更多相关文章

  1. windows核心编程 - 线程同步机制

    线程同步机制 常用的线程同步机制有很多种,主要分为用户模式和内核对象两类:其中 用户模式包括:原子操作.关键代码段 内核对象包括:时间内核对象(Event).等待定时器内核对象(WaitableTim ...

  2. (转)Windows驱动编程基础教程

    版权声明     本书是免费电子书. 作者保留一切权利.但在保证本书完整性(包括版权声明.前言.正文内容.后记.以及作者的信息),并不增删.改变其中任何文字内容的前提下,欢迎任何读者 以任何形式(包括 ...

  3. Windows游戏编程之从零开始d

    Windows游戏编程之从零开始d I'm back~~恩,几个月不见,大家还好吗? 这段时间真的好多童鞋在博客里留言说或者发邮件说浅墨你回来继续更新博客吧. woxiangnifrr童鞋说每天都在来 ...

  4. 《Windows核心编程》读书笔记 上

    [C++]<Windows核心编程>读书笔记 这篇笔记是我在读<Windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的思考和对 ...

  5. 【Windows】windows核心编程整理(上)

    小续 这是我11年看<windows核心编程>时所作的一些笔记,现整理出来共享给大家 windows核心编程整理(上) windows核心编程整理(下) 线程的基础知识 进程是不活泼的,进 ...

  6. Windows下编程--模拟时钟的实现

    windows下编程--模拟时钟的实现: 主要可以分为几个步骤: (1)   编写按键事件处理(启动和停止时钟) (2)   编写时钟事件处理,调用显示时钟函数 (3)   编写显示时钟函数,要调用显 ...

  7. C++Windows核心编程读书笔记

    转自:http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E6%96%87/71405.shtml "C++Windows核心编程读书笔 ...

  8. 【转】《windows核心编程》读书笔记

    这篇笔记是我在读<Windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的思考和对实现的推断,因此不少条款和Windows实际机制可能有出入 ...

  9. windows多线程编程星球(一)

    以前在学校的时候,多线程这一部分是属于那种充满好奇但是又感觉很难掌握的部分.原因嘛我觉得是这玩意儿和编程语言无关,主要和操作系统的有关,所以这部分内容主要出现在讲原理的操作系统书的某一章,看完原理是懂 ...

随机推荐

  1. nodejs内存溢出 FATAL ERROR: CALL_AND_RETRY_0 Allocation failed – process out of memory

    spa项目整体迁移转为ssr后,改动之后部署一切还好,就是突然有一天访问人数太多,node进程很容易就挂了自动重启. 最后经过压力测试,考虑到是堆内存溢出的问题,就报错误:FATAL ERROR: C ...

  2. 使用docker部署nginx+tomcat架构(2):访问mysql数据库

    上一篇完成了通过docker部署nginx+tomcat的基础软件架构,但是距离一个真正可用的软件架构还差得很远.其中最重要的一点是缺少数据库这个角色的存在,那么本篇就来完善这一点. 废话少说,直接进 ...

  3. orcle not like不建议使用(not like所踩过的坑!)

      1.情景展示 现在有一张表,需要将表中某字段的值不是以指定字符开头的列进行删除,如何实现? 2.问题分析 错误方案一:同事想到的是:这种方式 咱们来看一下,这个表总共有多少条数据 本来表数据总共才 ...

  4. udev只能修改Linux 网口名称,无法修改/dev目录下的设备名称

    NAME The name to use for a network interface. The name of a device node cannot be changed by udev, o ...

  5. CentOS 7.6 安装Python3.7.2 多版本共存

    CentOS 7.6 默认安装了 Python 2.7.5 准备环境 yum install git gcc gcc-c++ make automake autoconf libtool pcre p ...

  6. bolt继承关系和区别

    先上个图:  具体区别: IRichBolt/IBasicBolt 区别IRichBolt和IBasicBolt IRichBolt继承自IBolt和IComponent.IBasicBolt继承自I ...

  7. Selenium基础教程(二)环境搭建

    一.环境搭建 (1)初学者最佳环境: Python 2.7 + Selenium 2+ Firefox 46 (2)喜欢尝新的环境: Python 3.6 + Selenium 3+ Firefox ...

  8. python实现队列结构

    # -*- coding:utf-8 -*- # __author__ :kusy # __content__:文件说明 # __date__:2018/10/8 13:49 class MyQueu ...

  9. Go学习笔记之Map

    Go学习笔记之Map Map 引用类型,哈希表.map的key必须可以比较相等,除了slice, map, function的内建类型都可以作为key.struct类型不包含上述字段,也可作为key. ...

  10. python+requests+unittest 接口ddt测试

    以数据驱动的形式,将用例维护在py文件中 源码分析: 变量定义 publicParameters.py """ 公共参数 , 按照各公司实情,自行编写 "&qu ...