《Windows API每日一练》7.1 计时器基础知识

计时器(Timer)是一种在编程中用于测量时间间隔的机制。它允许程序在指定的时间间隔内执行特定的操作或触发事件。

本节必须掌握的知识点:

        计时器

7.1.1 计时器

我们可以调用SetTimer函数为自己的Windows程序分配一个计时器。SetTimer包含一个无符号整型参数,该参数指定了时间间隔的长短,为一毫秒(millisecond)到4 294 967 295 毫秒(将近50天)。这个参数也表示Windows给程序发送WM_TIMER消息的频率。例如, 1000毫秒就是要求Windows每一秒钟向你的程序发送一条WM_TIMER消息。

当程序不再需要计时器时,它可调用KillTimer函数停止计时器的消息。在处理 WM_TIMER消息时调用KillTimer函数可以实现一个“一次性”的计时器。KillTimer函数会淸除消息队列中任何没被处理的WM_TIMER消息。调用了 KillTimer之后,程序就不会再收到WM_TIMER消息了。

       ■Windows系统计时器

在 Windows 系统中,计时器的实现原理涉及到系统时钟和消息循环。

Windows 系统中的计时器通常使用以下两种方式实现:

●基于时间片的计时器(基于轮询):这种计时器的实现方式是在应用程序的消息循环中以固定时间间隔进行轮询。应用程序通过在消息循环中处理 WM_TIMER 消息来执行特定的操作。WM_TIMER 消息会周期性地发送给应用程序的消息队列,以通知计时器事件的发生。

应用程序可以使用 SetTimer 函数来创建一个定时器。该函数指定计时器的时间间隔和回调函数,并返回一个计时器 ID。然后,在消息循环中,应用程序通过处理 WM_TIMER 消息来执行相应的操作。

这种基于时间片的计时器适用于较低精度的计时需求,例如执行周期性的任务或更新用户界面。

●高精度计时器(Multimedia Timers):对于需要更高精度和准确性的计时需求,Windows 提供了高精度计时器。高精度计时器使用系统时钟的硬件定时器来实现,提供了更高的计时精度。

应用程序可以使用 timeSetEvent 函数来创建一个高精度计时器。该函数指定计时器的时间间隔、回调函数和其他参数,并返回一个计时器 ID。计时器事件触发时,系统会调用指定的回调函数。

高精度计时器适用于需要更精确计时的场景,例如音频和视频处理、实时数据采集等。

无论是基于时间片的计时器还是高精度计时器,它们的实现都依赖于系统时钟和消息循环。系统时钟提供了时间基准,用于确定计时器事件的发生时间。消息循环负责接收和处理计时器相关的消息,以便应用程序可以在计时器事件发生时执行相应的操作。

需要注意的是,计时器的精度可能受到系统负载、硬件性能和操作系统版本等因素的影响。因此,在实际应用中,如果需要更高精度的计时器,可以使用高精度计时器,并进行适当的性能测试和调优。

基于时间片的计时器

Windows的应用程序并不截获BIOS中断。Windows本身会处理硬件中断,应用程序不需介入。对于当前所设定的每一个计时器,Windows都会保持一个计数值,硬件时钟滴答每出现一次,这个值会减1。当计数值减到0,Windows会把一个WM_TIMER消息放到适当的应用程序的消息队列中,同时把计数值重新设置回它的原始值。

由于Windows应用程序是通过正常的消息队列来接收WM_TIMER消息,所以你绝对不用担心程序在处理其他任务时会被突然而来的WM_TIMER消息所“中断” 。因此计时器与键盘和鼠标相似:驱动程序会处理异步硬件中断事件,Windows则将这些事件转换为有序的、有组织的和系列化的消息。

在Windows 98上,计时器具有与底层PC计时器相同的55毫秒的周期。而在Windows NT上,计时器的周期大约是10毫秒。

Windows应用程序不能接收比上述频率更高的WM_TIMER消息,也就是说在 Windows 98上约为每秒18.2次,而在Windows NT上为每秒100次。Windows会通过 SetTimer把指定的时间间隔舍入到时钟滴答的整数倍。例如,1000亳秒时间段被54.925除是18.207个时钟滴答,它被舍入到18个时钟滴答,因此实际的间隔是989毫秒。如果时间间隔被设置为少于55毫秒,每个时钟滴答都将产生一个WM_TIMER消息。

       ■计时器同步

因为计时器是基于硬件计时器的中断,程序员有时会被误导,认为他们的程序可能会被异步中断打断后被迫去处理WM_TIMER消息。

其实WM_TIMER消息并不是异步的。WM_TIMER消息被放在正常的消息队列中,并和其他的消息一同排队等候处理。因此如果你在调用SetTimer函数时指定1000毫秒,并不能保证程序每秒钟或者每989毫秒(如我前面说过的)就收到一个WM_TIMER消息。如果你的程序处于忙的状态超过一秒钟,它就会在那个时间内得不到任何WM_TIMER消息。本章提供的程序便是证明。事实上,Windows处理WM_TIMER消息和处理WM_PAINT消息很类似。这两种消息都是低优先级的,只有当消息队列中没有其他消息时,程序才会收到它们。

WM_TIMER消息还在另一方面与WM_PAINT消息极为类似。Windows并不会连续不断地产生多个WM_TIMER消息到消息队列中。相反,Windows把在消息队列里的多个 WM_TIMER消息结合成一条消息。这样,应用程序不会同时收到大量的WM_TIMER消息,尽管它可能会收到靠得很近的两个WM_TIMER消息。同时,应用程序并不知道有多少这样的WM_TIMER消息在这个过程中“丢失”了。

因此,一个时钟程序不能通过计算它所收到的WM_TIMER消息个数来确认已过去多长时间。WM_TIMER消息只能告诉应用程序,更新的时间到了。在本章的后面,我们会写两个时钟程序,它们每秒钟更新一次,我们将准确地看到它是如何实现的。

为方便起见,我将假设计时器每秒钟收到一个WM_TIMER消息。但是请记住,这些消息不是精确的时钟滴答中断。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/37407.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pygame在mobaxterm上无法显示屏幕

在mobaxterm上的linux系统(这里测试的是ubuntu系统)上运行pygame时,在运行代码 pygame.display.init()展示窗口时会显示pygame.error: windows not available的错误。 这是因为linux下的窗口展示配置与windows不同,windows下按 …

C++实现简化版Qt信号槽机制(2):增加内存安全保障

在上一篇文章中《C实现一个简单的Qt信号槽机制》,我们基于前面的反射代码实现了信号槽的功能。 但是上一篇的代码中没有对象生命周期管理的机制,如果在对象的生命周期结束后还存在未断开的信号和槽连接,那么信号触发时可能会尝试访问已经被析…

ValidateAntiForgeryToken、AntiForgeryToken 防止CSRF(跨网站请求伪造)

用途&#xff1a;防止CSRF&#xff08;跨网站请求伪造&#xff09;。 用法&#xff1a;在View->Form表单中: aspx&#xff1a;<%:Html.AntiForgeryToken()%> razor&#xff1a;Html.AntiForgeryToken() 在Controller->Action动作上&#xff1a;[ValidateAntiForge…

Java的IO体系

目录 1、Java的IO体系2、IO的常用方法3、Java中为什么要分为字节流和字符流4、File和RandomAccessFile5、Java对象的序列化和反序列化6、缓冲流7、Java 的IO流中涉及哪些设计模式 1、Java的IO体系 IO 即为 input 输入 和 output输出 Java的IO体系主要分为字节流和字符流两大类…

java对word文档转图片,转PDF

话不多说&#xff0c;直接入题 先引包 <dependency><groupId>com.luhuiguo</groupId><artifactId>aspose-words</artifactId><version>23.1</version></dependency> word文档转图片 import com.aspose.words.Document; impor…

防爆配电箱航空插头正确安装

防爆配电箱航空插头的安装确实有特殊要求&#xff0c;这些要求旨在确保配电箱在潜在危险环境中的安全运行。以下是一些关键的安装要求&#xff1a; 安装环境&#xff1a;防爆配电箱应安装在危险区域之外的安全地点&#xff0c;远离潜在的爆炸源和危险物质。安装环境应保持干燥、…

springboot使用feign调用不依赖cloud

在使用spring boot调用第三方api中&#xff0c;常用的是okhttp、apache http client等&#xff0c;但是直接使用下来还是有点繁琐&#xff0c;需要手动转换实体。 在springcloud中有个openfeign调用&#xff0c;第一次体验到调用接口还能这么丝滑。注解写道接口上&#xff0c;…

17859划分准则小结

17859《划分准则》 发布时间&#xff1a;1999.9.13 实施时间&#xff1a;2001.1.1 计算机信息系统安全保护能力的五个等级&#xff1a; 第一级&#xff1a;用户自主保护级 第二级…

数据结构简介

在容器的基础之上&#xff0c;java引入了数据结构的概念。数据结构可以简单地理解成是一个以特定的布局方式来存储数据的容器。但是我个人觉得这种理解方式不太合理&#xff0c;根据我们学的数据结构的内容&#xff0c;我更倾向于数据结构是数据在容器中的布局方式&#xff0c;…

rtthread stm32h743的使用(十一)spi设备使用

我们要在rtthread studio 开发环境中建立stm32h743xih6芯片的工程。我们使用一块stm32h743及fpga的核心板完成相关实验&#xff0c;核心板如图&#xff1a; 1.建立新工程&#xff0c;选择相应的芯片型号及debug引脚及调试器 2.编译下载&#xff0c;可以看到串口打印正常 3.…

Python商务数据分析知识专栏(一)——Python编程基础

Python商务数据分析知识专栏&#xff08;一&#xff09;——Python编程基础 一、认识python二、编写python程序三、认识python数据结构四、条件判断及分支语句五、使用def定义函数六、认识面向对象七、读取文件数据八、模块和第三方库专栏一&#xff08;Python基础&#xff09;…

c++ 解决区间最大数和矩阵最大面积

给定一个实数序列&#xff0c;设计一个最有效的算法&#xff0c;找到一个总和数最大的区间等于某个事先给定的数字。 我们可以使用前缀和和哈希表来设计一个高效的算法。这个算法的时间复杂度是 O(n)&#xff0c;空间复杂度也是 O(n)。 #include <vector> #include <…

python查找支撑数 青少年编程电子学会python编程等级考试三级真题解析2022年3月

目录 python查找支撑数 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序代码 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python查找支撑数 2022年3月 python编程等级考试级编程题 一、题目要求…

RabbitMQ 的经典问题

文章目录 前言一、防止消息丢失1.1 ConfirmCallback/ReturnCallback1.2 持久化1.3 消费者确认消息 二、防止重复消费三、处理消息堆积四、有序消费消息五、实现延时队列六、小结推荐阅读 前言 当设计和运维消息队列系统时&#xff0c;如 RabbitMQ&#xff0c;有几个关键问题需…

第100+13步 ChatGPT学习:R实现决策树分类

基于R 4.2.2版本演示 一、写在前面 有不少大佬问做机器学习分类能不能用R语言&#xff0c;不想学Python咯。 答曰&#xff1a;可&#xff01;用GPT或者Kimi转一下就得了呗。 加上最近也没啥内容写了&#xff0c;就帮各位搬运一下吧。 二、R代码实现决策树分类 &#xff08;…

【漏洞复现】宏景HCM人力资源信息管理系统——任意文件读取漏洞

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现测试工具 漏洞描述 宏景HCM人力资源信息管理系统是一款全面覆盖人力资源管理各模块…

docker pull 镜像的时候遇到Pulling fs layer问题

最近遇到一个很奇怪的问题,docker pull 镜像的时候,总是出现Pulling fs layer问题,导致镜像拉取不成功,以前是安装好docker,正常拉取镜像都是没什么问题的,在这里记录一下这个问题的解决方法,当然,可能并不通用。 1、进入阿里云容器服务 地址:https://cr.console.aliy…

Spring Boot中的热部署配置

Spring Boot中的热部署配置 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将探讨如何在Spring Boot项目中实现热部署配置&#xff0c;提升开发效率和项…

C++实现Qt的信号+槽功能

在 Visual Studio (VS) 上使用 C 实现类似 Qt 的信号和槽机制是完全可能的&#xff0c;但 Qt 的信号和槽系统是基于其特定的元对象系统&#xff08;Meta-Object System, MOC&#xff09;的&#xff0c;这需要一些特定的预处理器和代码生成步骤。 如果你不想使用 Qt&#xff0c;…

vue路由传参和react 路由传参

路由跳转的方式 1、声明式导航 <router-link to"导航的地址"> 2、编程式导航 编程式导航有三种方法来进行导航 router.push router.replace router.go params传参和query传参 1、 params 传参(不在URL中显示参数) 在父路由跳转到子路由时&#xff0c;也可…