vc程序计时器(转)

VC 计时(三种方式) 三种计时方式: (1)WM_TIMER消息映射; (2)GetTickCount(),误差不大于1ms (3)QueryPerformanceCounter(),系统时间精度 立即下载

1 使用time_t time( time_t * timer )    精确到秒

  计算时间差使用double difftime( time_t timer1, time_t timer0 )

 

2 使用clock_t clock() 得到的是CPU时间    精确到1/CLOCKS_PER_SEC秒

3 使用DWORD GetTickCount() 得到的是系统运行的时间 精确到毫秒

4 如果使用MFC的CTime类,可以用CTime::GetCurrentTime() 精确到秒

5 要获取高精度时间,可以使用

    BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency)获取系统的计数器的频率

    BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount)获取计数器的值

    然后用两次计数器的差除以Frequency就得到时间。

6 还有David的文章中提到的方法:

    Multimedia Timer Functions

    The following functions are used with multimedia timers.

    timeBeginPeriod/timeEndPeriod/timeGetDevCaps/timeGetSystemTime

    timeGetTime/timeKillEvent/TimeProc/timeSetEvent  精度很高

Q:GetTickCount()函数,说是毫秒记数,是真的吗,还是精确到55毫秒?

A:

GetTickCount()和GetCurrentTime()都只精确到55ms(1个tick就是55ms)。如果要精确到毫秒,应该使用timeGetTime函数或QueryPerformanceCounter函数。具体例子可以参考QA001022 "VC++中使用高精度定时器"、QA001813 "如何在Windows实现准确的定时"和QA004842 "timeGetTime函数延时不准"。

Q:vc++怎样获取系统时间,返回值是什么类型的变量呢?

GetSystemTime返回的是格林威志标准时间

GetLocalTime,和上面用法一样,返回的是你所在地区的时间,中国返回的是北京时间

 

VOID GetSystemTime(

LPSYSTEMTIME lpSystemTime // address of system time structure

);

函数就可以获得了,其中LPSYSTEMTIME 是个结构体

含:年,月,日,周几,小时,分,秒,毫秒。

#include  <mmsystem.h>

#pragma comment(lib,"winmm.lib")

 

timegettime的标称是毫秒级别

但是实际上只能精确到50毫秒

 

 

使用CPU时间戳进行高精度计时

 

  对关注性能的程序开发人员而言,一个好的计时部件既是益友,也是良师。计时器既可以作为程序组件帮助程序员精确的控制程序进程,又是一件有力的调试武器,在有经验的程序员手里可以尽快的确定程序的性能瓶颈,或者对不同的算法作出有说服力的性能比较。

 

  在Windows平台下,常用的计时器有两种,一种是timeGetTime多媒体计时器,它可以提供毫秒级的计时。但这个精度对很多应用场合而言还是太粗糙了。另一种是QueryPerformanceCount计数器,随系统的不同可以提供微秒级的计数。对于实时图形处理、多媒体数据流处理、或者实时系统构造的程序员,善用QueryPerformanceCount/QueryPerformanceFrequency是一项基本功。

 

  本文要介绍的,是另一种直接利用Pentium CPU内部时间戳进行计时的高精度计时手段。以下讨论主要得益于《Windows图形编程》一书,第15页-17页,有兴趣的读者可以直接参考该书。关于RDTSC指令的详细讨论,可以参考Intel产品手册。本文仅仅作抛砖之用。

  在Intel Pentium以上级别的CPU中,有一个称为“时间戳(Time Stamp)”的部件,它以64位无符号整型数的格式,记录了自CPU上电以来所经过的时钟周期数。由于目前的CPU主频都非常高,因此这个部件可以达到纳秒级的计时精度。这个精确性是上述两种方法所无法比拟的。

 

  在Pentium以上的CPU中,提供了一条机器指令RDTSC(Read Time Stamp Counter)来读取这个时间戳的数字,并将其保存在EDX:EAX寄存器对中。由于EDX:EAX寄存器对恰好是Win32平台下C++语言保存函数返回值的寄存器,所以我们可以把这条指令看成是一个普通的函数调用。像这样:

 

inline unsigned __int64 GetCycleCount()

{

 __asm RDTSC

}

 

但是不行,因为RDTSC不被C++的内嵌汇编器直接支持,所以我们要用_emit伪指令直接嵌入该指令的机器码形式0X0F、0X31,如下:

 

inline unsigned __int64 GetCycleCount()

{

 __asm _emit 0x0F

 __asm _emit 0x31

}

 

以后在需要计数器的场合,可以像使用普通的Win32 API一样,调用两次GetCycleCount函数,比较两个返回值的差,像这样:

 

unsigned long t;

t = (unsigned long)GetCycleCount();

//Do Something time-intensive ...

t -= (unsigned long)GetCycleCount();

 

  《Windows图形编程》第15页编写了一个类,把这个计数器封装起来。有兴趣的读者可以去参考那个类的代码。作者为了更精确的定时,做了一点小小的改进,把执行RDTSC指令的时间,通过连续两次调用GetCycleCount函数计算出来并保存了起来,以后每次计时结束后,都从实际得到的计数中减掉这一小段时间,以得到更准确的计时数字。但我个人觉得这一点点改进意义不大。在我的机器上实测,这条指令大概花掉了几十到100多个周期,在Celeron 800MHz的机器上,这不过是十分之一微秒的时间。对大多数应用来说,这点时间完全可以忽略不计;而对那些确实要精确到纳秒数量级的应用来说,这个补偿也过于粗糙了。

 

这个方法的优点是:

 

1.高精度。可以直接达到纳秒级的计时精度(在1GHz的CPU上每个时钟周期就是一纳秒),这是其他计时方法所难以企及的。

 

2.成本低。timeGetTime 函数需要链接多媒体库winmm.lib,QueryPerformance* 函数根据MSDN的说明,需要硬件的支持(虽然我还没有见过不支持的机器)和KERNEL库的支持,所以二者都只能在Windows平台下使用(关于DOS平台下的高精度计时问题,可以参考《图形程序开发人员指南》,里面有关于控制定时器8253的详细说明)。但RDTSC指令是一条CPU指令,凡是i386平台下Pentium以上的机器均支持,甚至没有平台的限制(我相信i386版本UNIX和Linux下这个方法同样适用,但没有条件试验),而且函数调用的开销是最小的。

 

3.具有和CPU主频直接对应的速率关系。一个计数相当于1/(CPU主频Hz数)秒,这样只要知道了CPU的主频,可以直接计算出时间。这和QueryPerformanceCount不同,后者需要通过QueryPerformanceFrequency获取当前计数器每秒的计数次数才能换算成时间。

 

这个方法的缺点是:

 

1.现有的C/C++编译器多数不直接支持使用RDTSC指令,需要用直接嵌入机器码的方式编程,比较麻烦。

 

2.数据抖动比较厉害。其实对任何计量手段而言,精度和稳定性永远是一对矛盾。如果用低精度的timeGetTime来计时,基本上每次计时的结果都是相同的;而RDTSC指令每次结果都不一样,经常有几百甚至上千的差距。这是这种方法高精度本身固有的矛盾。

 

关于这个方法计时的最大长度,我们可以简单的用下列公式计算:

 

自CPU上电以来的秒数 = RDTSC读出的周期数 / CPU主频速率(Hz)

 

64位无符号整数所能表达的最大数字是1.8×10^19,在我的Celeron 800上可以计时大约700年(书中说可以在200MHz的Pentium上计时117年,这个数字不知道是怎么得出来的,与我的计算有出入)。无论如何,我们大可不必关心溢出的问题。

 

下面是几个小例子,简要比较了三种计时方法的用法与精度

 

//Timer1.cpp 使用了RDTSC指令的Timer类//KTimer类的定义可以参见《Windows图形编程》P15

//编译行:CL Timer1.cpp /link USER32.lib

#include <stdio.h>

#include "KTimer.h"

main()

{

 unsigned t;

 KTimer timer;

 timer.Start();

 Sleep(1000);

 t = timer.Stop();

 printf("Lasting Time: %d/n",t);

}

 

//Timer2.cpp 使用了timeGetTime函数

//需包含<mmsys.h>,但由于Windows头文件错综复杂的关系

//简单包含<windows.h>比较偷懒:)

//编译行:CL timer2.cpp /link winmm.lib

#include <windows.h>

#include <stdio.h>

 

main()

{

 DWORD t1, t2;

 t1 = timeGetTime();

 Sleep(1000);

 t2 = timeGetTime();

 printf("Begin Time: %u/n", t1);

 printf("End Time: %u/n", t2);

 printf("Lasting Time: %u/n",(t2-t1));

}

 

//Timer3.cpp 使用了QueryPerformanceCounter函数

//编译行:CL timer3.cpp /link KERNEl32.lib

#include <windows.h>

#include <stdio.h>

 

main()

{

 LARGE_INTEGER t1, t2, tc;

 QueryPerformanceFrequency(&tc);

 printf("Frequency: %u/n", tc.QuadPart);

 QueryPerformanceCounter(&t1);

 Sleep(1000);

 QueryPerformanceCounter(&t2);

 printf("Begin Time: %u/n", t1.QuadPart);

 printf("End Time: %u/n", t2.QuadPart);

 printf("Lasting Time: %u/n",( t2.QuadPart- t1.QuadPart));

}

 

////////////////////////////////////////////////

//以上三个示例程序都是测试1秒钟休眠所耗费的时间

file://测/试环境:Celeron 800MHz / 256M SDRAM 

//          Windows 2000 Professional SP2

//          Microsoft Visual C++ 6.0 SP5

////////////////////////////////////////////////

 

以下是Timer1的运行结果,使用的是高精度的RDTSC指令

Lasting Time: 804586872

 

以下是Timer2的运行结果,使用的是最粗糙的timeGetTime API

Begin Time: 20254254

End Time: 20255255

Lasting Time: 1001

 

以下是Timer3的运行结果,使用的是QueryPerformanceCount API

Frequency: 3579545

Begin Time: 3804729124

End Time: 3808298836

Lasting Time: 3569712

 

参考资料:

[YUAN 2002]Feng Yuan 著,英宇工作室 译,Windows图形编程,机械工业出版社,2002.4.,P15-17

 

倒计时器源码vc++6..0版(MFC ) 可以自己设置时间,修改标题,30秒提示等功能。使用VC6.0编写,部分功能不是十分完善,主要功能已经实现。 立即下载

相关推荐

VC 高精度计时器很好用

VC 高精度计时器,很好用的 VC 高精度计时器很好用

使用CPU时间戳进行高精度计时

使用CPU时间戳进行高精度计时

jiangxinyu的专栏 1021

VC++中使用普通计时器和多媒体高精度计时器

资源中是一个在VC++中使用普通计时器和多媒体高精度计时器的实例,可供参考。

SDK编程笔记 — 计时器篇

SDK编程笔记 — 计时器篇两个计时器API的讨论  SetTimer函数用于创建一个计时器,KillTimer函数用于销毁一个计时器。计时器属于系统资源,使用完应及时销毁。  SetTimer的函数原型如下:UINT_PTR SetTimer( HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFun

聚焦游戏和图形引擎开发技术 4805

Codex驱动AEDT完成无线充电仿真——从双线圈建模到三维电磁场动画

本文介绍了一个利用Codex、PyAEDT和Ansys Electronics Desktop 2025 R2实现双线圈无线充电系统自动建模与仿真的案例。通过简化模型(平面线圈+铁氧体磁芯),完成了从参数化建模、电磁场求解到后处理的全流程自动化,获得了耦合系数(k=0.17)、三维电磁场分布及多周期动态可视化效果。研究发现:线圈间距对传输效率影响最大(10-30mm间距时效率从40.2%降至5.57%),横向偏移15mm会使效率下降35%,而磁芯厚度增加带来的效率提升有限(3→7mm仅提高1.67%)。该框

sjjsjjsjjsjjsjj的博客 445

爬取信用中国里面的行政处罚

result字段名为行政处罚文书号、处罚决定日期、处罚内容、处罚金额、违法事实、处罚机关、公司名称,行政处罚次数。file_path=r'E:\Data analyze\python\行政处罚爬虫/'#路径需要按实际修改。writer = pd.ExcelWriter('统计.xlsx')# 写入Excel文件。src_workbook=file_path+r'行政处罚(名单).xls' #表格名称也要更改。# keyword = input("输入爬取的公司全称必须是全称")

qq_42863025的博客 1674

VC++中计时器的运用

 1、MFC中的计时原理:当你需要每隔一段时间执行一件事的的时候就需要使用SetTimer()函数了。 让我们先来看看SetTimer函数的原型:    UINT SetTimer(UINT nIDEvent,UINT nElapse,void(CALLBACK EXPORT *lpfnTimer)(HWND,UINT ,YINT ,DWORD)) 当使用SetTimer函数的时候

VC++/MFC的专栏 1万+

一文详细讲解CRM系统(附架构图、流程、功能介绍)

专为中小企业量身打造高性价比的数字化转型路径!企业如何用CRM才能真正做到降本增效?今天,就用一文讲清这些问题!读完本文,你将清楚得了解CRM的概念、框架、流程、功能、企业成功案例,文末还有常见问题解答。

Dabeishandong的博客 9925

Visual C++——定时器(计时器)SetTimer函数

基本概念 SetTimer函数用于创建一个计时器 KillTimer函数用于销毁一个计时器。 计时器属于系统资源,使用完应及时销毁。 API SetTimer的函数原型: UINT_PTR SetTimer(HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc ); 其中 hWnd是...

无限迭代中...... 9901

GeoScene Pro教程(002):GeoScenePro基础操作

GeoScenePro基础操作介绍。

WwLK123的博客 2460

强化学习(Q-learning、DQN) —— 理论、案例与交互式 GUI 实现

本文详细介绍了强化学习中基于值函数的 Q-learning 算法及深度强化学习的 DQN 方法,从基本理论、数学模型到算法流程均进行了全面阐述。通过迷宫导航、股票交易策略和机器人控制等典型案例,展示了强化学习在处理高维、非线性和时变问题中的强大适应性。为了帮助工程师和研究者更直观地理解强化学习的训练过程,本文还提供了一份基于 Python 与 PyQt6 实现的交互式 GUI 演示系统代码示例,用户可以在线调整参数,实时观察累计奖励和 Q 值的变化,从而更深入地理解算法收敛和策略演化的过程。

闲人编程的博客 1475

vc计时器数字重叠_VC计时器的一个使用心得

朱金灿最近使用VC的计时器。计时器一般是先设置一个Timer,然后响应WM_TIMER消息,然后销毁计时器。但是我发现在哪里设置计时器和销毁计时器是有讲究的。开始我的代码是这样的:CMainFrame::CMainFrame(){// TODO: add member initialization code hereSetTimer(1, 5000, 0);}// WM_TIMER消息响应函数vo...

weixin_42576467的博客 173

18、探索隐私工程技术的前沿:从理论到实践

本文深入探讨了隐私工程技术的核心概念、关键技术及其应用场景,分析了加密技术、访问控制和用户界面设计等在隐私保护中的作用,并结合数据库保护、物联网设备等实际场景进行阐述。同时,文章还讨论了隐私工程技术面临的挑战与未来发展趋势,提出了数据最小化原则、差分隐私、隐私增强技术等优化策略以及隐私设计、隐私影响评估等最佳实践,最后展望了新兴技术对隐私保护的影响及法规推动下的发展方向。

weixin_35307279的博客 373

VC计时器的一个使用心得

最近使用VC的计时器。计时器一般是先设置一个Timer,然后响应WM_TIMER消息,然后销毁计时器。但是我发现在哪里设置计时器和销毁计时器是有讲究的。 开始我的代码是这样的:CMain::CMain(){       // TODO: add member initialization code here       SetTimer(1, 5000, 0);}/

rsjrj的专栏 889

Codex 团队如何用自己的产品构建产品——整个 Spec 只有 10 个要点

OpenAI Codex团队采用极简产品开发模式,整个产品规格仅10个要点。团队50-100人长期仅1名PM,设计师代码量已超过工程师。产品负责人Alexander Embiricos透露,团队几乎不写详细文档,仅在需要协调时写简短要点。OpenAI采用独特规划哲学:只做8周内短期或长期方向性规划,拒绝中期路线图。2025年GPT-5.2 Codex发布后,模型能力突破催生了桌面应用开发。团队强调"让离代码最近的人做决策",PM角色转变为"填空者",设计师与工程师界限

347

三维点云转深度图

点云投影过程是将三维点云数据转化为二维图像坐标的关键步骤,它的实现涉及到相机内外参数的计算,包括相机的内部参数(如焦距和主点)和外部参数(如相机位置和方向)。具体来说,可以通过将每个点的三维坐标转换为相机坐标系下的坐标,然后使用相机内部参数和外部参数来计算在二维图像中的坐标。接着计算每个点的深度值,将深度值映射到像素值上,最后创建深度图像并将深度值赋给对应的像素值。这里需要注意的是,在将深度值映射到像素值上时,需要将像素值转换为 uchar 类型,否则在将深度值赋给像素值时会出现类型不匹配的错误。

点云兔子的博客 3171

VC计时器使用的一些总结

我使用的VC计时器主要使用的API是SetTimer和OnTimer两个,严格来说OnTimer并不算是API,只是一个执行器,另外还有啊KillTimer,但是本次并未用到,以后用到再行总结。 SetTimer(NULL,1,1000,NULL); NULL 默认是主进程调用 1:计时器的名称; 1000:时间间隔,单位是毫秒; NULL:使用OnTimer函数。 当不需要计

Ezio 861

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

VC中计时器的运用

什么时候我们需要用到SetTimer函数呢?当你需要每个一段时间执行一件事的的时候就需要使用SetTimer函数了。 让我们先来看看SetTimer函数的原型: UINT SetTimer(UINT nIDEvent,UINT nElapse,void(CALLBACK EXPORT *lpfnTimer)(HWND,UINT ,YINT ,DWORD)) 当使用SetTimer函数的时候,就会生

坚持到底 1854

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

关于VC中的Timer(转)

转自:http://blog.163.com/zzh2200_0@126/blog/static/31982333200791595559465/ 什么时候我们需要用到SetTimer函数呢?当你需要每个一段时间执行一件事的的时候就需要使用SetTimer函数了。 让我们先来看看 SetTimer函数的原型: UINT SetTimer(UINT nIDEvent,UINT nElapse,void(CALLBACK EXPORT *lpfnTimer)(HWND,UINT ,YINT ,DWORD)

流云 2371

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

VC应用程序中初始化界面的一种实现方法

VC应用程序中初始化界面的一种实现方法KEY WORDS: Spash Screen 非模式对话框级别:PrimerPHOTOSHOP在启动时,欢迎屏幕[Spash Screen]上会动态显示一些程序初始化时的信息,然后才进入工作界面,如果我们自己开发的程序能实现这个功能,一定能给软件增色不少。VC给我们开发者提供了一个小东东:Visual C++ Components-> Spl

3658
上一篇: 在Windows下编译OpenSSL(VS2005) 转
下一篇: c++primer学习笔记(二)
skilledprogrammer
博客等级 码龄19年 78粉丝 53原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值