通过异步程序调用(APC)实现的定时功能 CreateWaitableTimer和SetWaitableTimer函数

本文主要是介绍通过异步程序调用(APC)实现的定时功能 CreateWaitableTimer和SetWaitableTimer函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  定时器是一个在特定时间或者规则间隔被激发的内核对象。结合定时器的异步程序调用可以允许回调函数在任何定时器被激发的时候执行。本文的例子代码显示了如何实现。
  使用本定时器时,你需要把常量_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队 列的速度比处理的更快的话,则调用这些函数可能永远也不能返回。特别当定时等待的时间比起要求执行完全例程的时间更短的话,这种情况更容易发生。
2、当使用APC来实现定时器时,设置定时的线程不应该等待定时器的句柄。如果等待定时器的句柄的话,则唤起这个线程的原因是定时器被激活,而不是有实体 加入到APC队列中。这时线程将不再处于监听状态,所以完全例程也不会被调用。在本例中,Sleep()被用于将线程置于监听状态。在定时器激活后,如果 有实体被加入到此线程的APC队列中时,Sleep()就会唤醒此线程。

【示例代码】



原文参考:Using a Waitable Timer with an Asynchronous Procedure Call

这篇关于通过异步程序调用(APC)实现的定时功能 CreateWaitableTimer和SetWaitableTimer函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/574838

相关文章

Python使用python-can实现合并BLF文件

《Python使用python-can实现合并BLF文件》python-can库是Python生态中专注于CAN总线通信与数据处理的强大工具,本文将使用python-can为BLF文件合并提供高效灵活... 目录一、python-can 库:CAN 数据处理的利器二、BLF 文件合并核心代码解析1. 基础合

Python使用OpenCV实现获取视频时长的小工具

《Python使用OpenCV实现获取视频时长的小工具》在处理视频数据时,获取视频的时长是一项常见且基础的需求,本文将详细介绍如何使用Python和OpenCV获取视频时长,并对每一行代码进行深入解析... 目录一、代码实现二、代码解析1. 导入 OpenCV 库2. 定义获取视频时长的函数3. 打开视频文

golang版本升级如何实现

《golang版本升级如何实现》:本文主要介绍golang版本升级如何实现问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录golanwww.chinasem.cng版本升级linux上golang版本升级删除golang旧版本安装golang最新版本总结gola

MySQL 中的 CAST 函数详解及常见用法

《MySQL中的CAST函数详解及常见用法》CAST函数是MySQL中用于数据类型转换的重要函数,它允许你将一个值从一种数据类型转换为另一种数据类型,本文给大家介绍MySQL中的CAST... 目录mysql 中的 CAST 函数详解一、基本语法二、支持的数据类型三、常见用法示例1. 字符串转数字2. 数字

SpringBoot中SM2公钥加密、私钥解密的实现示例详解

《SpringBoot中SM2公钥加密、私钥解密的实现示例详解》本文介绍了如何在SpringBoot项目中实现SM2公钥加密和私钥解密的功能,通过使用Hutool库和BouncyCastle依赖,简化... 目录一、前言1、加密信息(示例)2、加密结果(示例)二、实现代码1、yml文件配置2、创建SM2工具

Mysql实现范围分区表(新增、删除、重组、查看)

《Mysql实现范围分区表(新增、删除、重组、查看)》MySQL分区表的四种类型(范围、哈希、列表、键值),主要介绍了范围分区的创建、查询、添加、删除及重组织操作,具有一定的参考价值,感兴趣的可以了解... 目录一、mysql分区表分类二、范围分区(Range Partitioning1、新建分区表:2、分

MySQL 定时新增分区的实现示例

《MySQL定时新增分区的实现示例》本文主要介绍了通过存储过程和定时任务实现MySQL分区的自动创建,解决大数据量下手动维护的繁琐问题,具有一定的参考价值,感兴趣的可以了解一下... mysql创建好分区之后,有时候会需要自动创建分区。比如,一些表数据量非常大,有些数据是热点数据,按照日期分区MululbU

MySQL中查找重复值的实现

《MySQL中查找重复值的实现》查找重复值是一项常见需求,比如在数据清理、数据分析、数据质量检查等场景下,我们常常需要找出表中某列或多列的重复值,具有一定的参考价值,感兴趣的可以了解一下... 目录技术背景实现步骤方法一:使用GROUP BY和HAVING子句方法二:仅返回重复值方法三:返回完整记录方法四:

Python内置函数之classmethod函数使用详解

《Python内置函数之classmethod函数使用详解》:本文主要介绍Python内置函数之classmethod函数使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 类方法定义与基本语法2. 类方法 vs 实例方法 vs 静态方法3. 核心特性与用法(1编程客

IDEA中新建/切换Git分支的实现步骤

《IDEA中新建/切换Git分支的实现步骤》本文主要介绍了IDEA中新建/切换Git分支的实现步骤,通过菜单创建新分支并选择是否切换,创建后在Git详情或右键Checkout中切换分支,感兴趣的可以了... 前提:项目已被Git托管1、点击上方栏Git->NewBrancjsh...2、输入新的分支的