求教,C++定时器回调函数QueryPerformance系列函数

Visual C++实现微秒级精度定时器 - CSDN博客
Visual C++实现微秒级精度定时器
在工业生产控制系统中,有许多需要定时完成的操作,如:定时显示当前时间,定时刷新屏幕上的进度条,上位机定时向下位机发送命令和传送数据等。特别是在对控制性能要求较高的控制系统和数据采集系统中,就更需要精确定时操作。众所周知,Windows是基于消息机制的系统,任何事件的执行都是通过发送和接收消息来完成的。这样就带来了一些问题,如一旦计算机的CPU被某个进程占用,或系统资源紧张时,发送到消息队列中的消息就暂时被挂起,得不到实时处理。因此,不能简单地通过Windows消息引发一个对定时要求严格的事件。另外,由于在Windows中已经封装了计算机底层硬件的访问,所以要想通过直接利用访问硬件来完成精确定时,也比较困难。在实际应用时,应针对具体定时精度的要求,采取与之相适应的定时方法。
本实例实现了一中微秒级的精确定时,的界面提供了两个&Edit&编辑框,其中一个编辑框输入用户理想的定时长度,另外一个编辑框返回实际的时间长度,经过大量的实验测试,一般情况下误差不超过5个微秒。的运行界面如图一所示:
图&1实现微秒级的精确定时器
1.&&&&&&&实现方法
Visual C++中提供了很多关于时间操作的函数,利用它们控制能够精确地完成定时和计时操作。Visual
C++中的WM_TIMER消息映射能进行简单的时间控制。首先调用函数SetTimer()设置定时间隔(退出时别忘了调用和SetTimer()配对使用的KillTimer()函数),如SetTimer(0,200,NULL)即为设置200ms的时间间隔。然后在应用中增加定时响应函数OnTimer(),并在该函数中添加响应的处理语句,用来完成到达定时时间的操作。这种定时方法非常简单,但其定时功能如同Sleep()函数的延时功能一样,精度非常低,只可以用来实现诸如位图的动态显示等对定时精度要求不高的情况。
微软公司在其多媒体Windows中提供了精确定时器的底层API支持。利用多媒体定时器可以很精确地读出系统的当前时间,并且能在非常精确的时间间隔内完成一个事件、函数或过程的调用。利用多媒体定时器的基本功能,可以通过两种方法实现精确定时。
1.&&&&&&&&使用timeGetTime()函数,该函数定时精度为ms级,返回从Windows启动开始所经过的时间。由于使用该函数是通过查询的方式进行定时控制的,所以,应该建立定时循环来进行定时事件的控制。
2.&&&&&&&&使用timeSetEvent()函数,该函数原型如下:
MMRESULT&timeSetEvent(UINT&uDelay,
&&&&&&&&&&&&&&&&&&&&&&UINT&uResolution,
&&&&&&&&&&&&&&&&&&&&&&LPTIMECALLBACK&lpTimeProc,
&&&&&&&&&&&&&&&&&&&&&&DWORD&dwUser,
&&&&&&&&&&&&&&&&&&&&&&UINT&fuEvent);
该函数的参数说明如下:参数uDelay表示延迟时间;参数uResolution表示时间精度,在Windows中缺省值为1lpTimeProc表示回调函数,为用户自定义函数,定时调用;&参数dwUser表示用户提供的回调数据;参数fuEvent为定时器的事件类型,TIME_ONESHOT表示执行一次;TIME_PERIODIC:周期性执行。具体应用时,可以通过调用timeSetEvent()函数,将需要周期性执行的任务定义在lpTimeProc回调函数中(如:定时采样、控制等),从而完成所需处理的事件。需要注意的是:任务处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后,应及时调用timeKillEvent()将之释放。下面这段代码的主要功能是设置两个时钟定时器,一个间隔是1ms,一个间隔是2s。每执行一次,把当前系统时钟值输入文件&cure.out&中,以比较该定时器的精确度。
#define&ONE_MILLI_SECOND&1&//&定义1ms和2s时钟间隔,&以ms为单位&;
#define&TWO_SECOND&2000
#define&TIMER_ACCURACY&1&//&定义时钟分辨率,&以ms为单位
UINT&wTimerRes_1ms,&wTimerRes_2s;&//&定义时间间隔
UINT&wAccuracy;&//&定义分辨率
UINT&TimerID_1ms,&TimerID_2s;&//&定义定时器句柄
////////////////////////////////////////////////////////////////////////////
CCureApp::CCureApp() :&fout(&cure.out&,&ios::out)&//&打开输出文件&cure.out&;
&&&&//&给时间间隔变量赋值
&&&&wTimerRes_1ms&=&ONE_MILLI_SECOND;
&&&&wTimerRes_2s&=&TWO_SECOND;
&&&&TIMECAPS&tc;
&&&&//&利用函数timeGetDevCaps取出系统分辨率的取值范围,&如果无错则继续;
&&&&if(timeGetDevCaps(&tc,sizeof(TIMECAPS))==TIMERR_NOERROR)
&&&&&&&&wAccuracy&=&min(max(tc.wPeriodMin,&//分辨率的值不能超出系统的取值范围
&&&&&&&&&&&&TIMER_ACCURACY),&tc.wPeriodMax);
&&&&&&&&//&调用timeBeginPeriod函数设置定时器的分辨率
&&&&&&&&timeBeginPeriod(wAccuracy);
&&&&&&&&//&设置定时器
&&&&&&&&InitializeTimer();
CCureApp::~CCureApp()
&&&&fout&&&&&结束时钟&&&&&endl;&//&结束时钟
&&&&timeKillEvent(TimerID_1ms);&//&删除两个定时器
&&&&timeKillEvent(TimerID_2s);&//&删除设置的分辨率
&&&&timeEndPeriod(wAccuracy);
void&CCureApp::InitializeTimer()
&&&&StartOneMilliSecondTimer();
&&&&StartTwoSecondTimer();
// 1ms定时器的回调函数,&类似于中断处理程序,&一定要声明为全局PASCAL函数,
//&否则编译会有问题
void&PASCAL&OneMilliSecondProc(UINT&wTimerID,&UINT&msg,&DWORD&dwUser,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&DWORD&dwl,&DWORD&dw2)
&&&&//&定义计数器
&&&&static&int&ms&=&0;
&&&&CCureApp&*app&= (CCureApp&*)dwUser;
&&&&//&取得系统时间,以ms为单位
&&&&DWORD&osBinaryTime&=&GetTickCount();
&&&&//&输出计数器值和当前系统时间
&&&&app-&fout&&& ++ms&&&&&:1ms:&;
//&加装1ms定时器
void&CCureApp::StartOneMilliSecondTimer()
&&&&if((TimerID_1ms&=&timeSetEvent(wTimerRes_1ms,&wAccuracy,
&&&&&&&&(LPTIMECALBACK)&OneMilliSecondProc,&//&回调函数;
&&&&&&&&(DWORD)this,&&//&用户传送到回调函数的数据;
&&&&&&&&TIME_PERIODIC)) ==&0)//&周期调用定时处理函数;
&&&&&&&&AfxMessageBox(&不能进行定时!&,&MB_OK&|&MB_ICONASTERISK);
&&&&&&&&fout&&&&&16ms&计&时:&&&&&endl;&//&不等于0表明加装成功
在精度要求较高的情况下,如要求定时误差不大于1ms时,还可以利用GetTickCount()函数返回自计算机启动后的时间,该函数的返回值是DWORD型,表示以ms为单位的计算机启动后经历的时间间隔。通过两次调用GetTickCount()函数,然后控制它们的差值来取得定时效果.下列的代码可以实现50ms的精确定时,其误差是毫秒级的。
//&起始值和中止值
DWORD&dwStart,&dwStop;
dwStop&=&GetTickCount();
while(TRUE)
&&&&//&上一次的中止值变成新的起始值
&&&&dwStart&=&dwStop;&//&此处添加相应控制语句
&&&&&&&&dwStop&=&GetTickCount();
&&&&while(dwStop&-&50&&&dwStart);
用上述两种方式取得的定时效果虽然在许多场合已经满足实际的要求,但由于它们的精度只有毫秒级的,而且在要求定时时间间隔小时,实际定时误差大。对于精确度要求更高的定时操作,则应该使用QueryPerformanceFrequency()和QueryPerformanceCounter()函数。这两个函数是Visual
C++提供并且仅供Windows 95及其后续版本使用,其精度与CPU的时钟频率有关,它们要求计算机从硬件上支持精确定时器。QueryPerformanceFrequency()函数和QueryPerformanceCounter()函数的原型如下:
BOOL&QueryPerformanceFrequency(LARGE_INTEGER&*lpFrequency);
BOOL&QueryPerformanceCounter(LARGE_INTEGER&*lpCount);
上述两个函数的参数的数据类型LARGE_INTEGER既可以是一个8字节长的整型数,也可以是两个4字节长的整型数的联合结构,其具体用法根据编译器是否支持64位而定。该类型的定义如下:
typedef&union&_LARGE_INTEGER
&&&&struct
&&&&&&&&DWORD&LowPart;&// 4字节整型数
&&&&&&&&LONG&HighPart;&// 4字节整型数
&&&&LONG&QuadPart;&// 8字节整型数
}LARGE_INTEGER;
使用QueryPerformanceFrequency()和QueryPerformanceCounter()函数进行精确定时的步骤如下:
1.&&&&&&&&首先调用QueryPerformanceFrequency()函数取得高精度运行计数器的频率f,单位是每秒多少次(n/s),此数一般很大;
2.&&&&&&&&在需要定时的代码的两端分别调用QueryPerformanceCounter()以取得高精度运行计数器的数值n1、n2,两次数值的差值通过f换算成时间间隔,t=(n2-n1)/f,当t大于或等于定时时间长度时,启动定时器;
2.&&&&&&&步骤
1.&&&&&&&&启动Visual C++6.0,生成一个基于对话框的应用,将命名为&HightTimer&;
2.&&&&&&&&在对话框面板中添加,布局如图一所示,其中包含两个静态文本框,两个编辑框和两个按纽。上面和下面位置的编辑框的ID分别为IDC_TEST和IDC_ACTUAL,&EXIT&按纽的ID为IDOK,&TEST&按纽ID为ID_TEST;
3.&&&&&&&&通过Class Wizard添加成员变量,两个编辑框分别对应为DWORD
m_dwTest和DWORD m_dwAct,另外添加&TEST&按纽的鼠标单击消息处理函数;
4.&&&&&&&&添加代码,编译运行。
3.&&&&&&&代码
/////////////////////////////////////////////////////////////////////////
//&功能:执行实际的延时功能, Interval&参数为需要执行的延时与时间有关的数量,
//&此函数返回执行后实际所用的时间有关的数量&;
LARGE_INTEGER&MySleep(LARGE_INTEGER&Interval)
&&&&LARGE_INTEGER&privious,&current,&Elapse;
&&&&QueryPerformanceCounter(&privious);
&&&&current&=&privious;
&&&&while&(current.QuadPart&-&privious.QuadPart&&&Interval.QuadPart)
&&&&&&&&QueryPerformanceCounter(&current);
&&&&Elapse.QuadPart&=&current.QuadPart&-&privious.QuadPart;
&&&&return&Elapse;
void&CHightTimerDlg::OnTest()
&&&&// TODO: Add your control notification handler code here
&&&&UpdateData(TRUE);&//&取输入的测试时间值到与编辑框相关联的成员变量m_dwTest中;
&&&&LARGE_INTEGER&frequence;
&&&&//&取高精度运行计数器的频率,&若硬件不支持则返回FALSE
&&&&if(!QueryPerformanceFrequency(&frequence))
&&&&&&&&MessageBox(&Your computer hardware doesn't support&
&&&&&&&&& the high-resolution performance counter&,
&&&&&&&&&Not Support&,&MB_ICONEXCLAMATION&|&MB_OK);
&&&&LARGE_INTEGER&test,&ret;
&&&&//&通过频率换算微秒数到对应的数量(与CPU时钟有关), 1秒&=
1000000微秒;
&&&&test.QuadPart&=&frequence.QuadPart&*&m_dwTest&/&1000000;
&&&&ret&=&MySleep(test);&//&调用此函数开始延时,&返回实际花销的数量&;
&&&&m_dwAct&= (DWORD)(1000000&*&ret.QuadPart&/&frequence.QuadPart);&//&换算到微秒数;
&&&&UpdateData(FALSE);&//&显示到对话框面板&;
4.&&&&&&&小结
本实例介绍了实现精确定时的不同方法,尤其是对于需要精确到微秒级别的定时处理,给出了实现的方法和代码,细心的读者朋友在运行的过程中可能会发现要求的定时长度和实际返回的时间长度还是有一些差异的,造成上述情况的原因是由于在进行定时处理时,还需要运行一些简单的循环代码,所以会产生微秒级的误差
转自:http://blog.csdn.net/jiangxinyu/article/details/6213040
本文已收录于以下专栏:
相关文章推荐
c++微秒级时间统计
一、使用clock()函数,获取毫秒级(ms)时间[1]
#include //clock()头文件
clock_t start = clock();
   {statement s...
C++毫秒以及纳秒级别的两种计时方式
在工业生产控制系统中,有许多需要定时完成的操作,如:定时显示当前时间,定时刷新屏幕上的进度条,上位机定时向下位机发送命令和传送数据等。特别是在对控制性能要求较高的控制系统和数据采集系统中,就更需要精确...
Visual C++实现微秒级精度定时器
自从上次封装微秒延时函数后,利用空闲时间试着封装一个微秒定时器(类似MFC定时器形式)使用起来效果还不错。关于定时器的几点介绍:
1.设计采用了自动释放定时器节点方式(增加虚析构函数在内部做...
一种制作微秒级精度定时器的方法(转贴)
本系列文章由zhmxy555编写,转载请注明出处。  http://blog.csdn.net/zhmxy555/article/details/7343337
作者:毛星云    邮箱: ha...
定时器的使用
定时器(Timer)对象可以每隔一段时间发出一个时间消息,程序一旦接收到此消息之后,便可以决定接下来要做哪些事情。这样的一个特性刚好可以适合播放静态的连续图片,产生动画的效...
他的最新文章
讲师:宋宝华
讲师:何宇健
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)一个简单定时器的实现(C++) - CSDN博客
一个简单定时器的实现(C++)
该定时器类继承一个Thread类(自定义),在线程函数里,每隔一定的时间,执行一次TimerHandler.
1 &setInterval 的时间间隔不能等于定时器要定时的总时间
2 Handle thread=::CreateThread(NULL,0,ThreadProc,this,0,p);
& & 线程创建使用的是Win32的API,因为线程也只是创建一次,属于极少创建线程的Case,所以可以使用。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include &iostream&
#include &time.h&
int main()
clock_t start = clock();
// Place your codes here...
// 指定运行次数
clock_t ends = clock();
cout &&&Running Time : &&&(double)(ends - start)/ CLOCKS_PER_SEC &&
// 每秒时钟的跳数
cout &&&Running Time : &&&ends - start &&& ms&&&
// 毫秒 ms
程序很简单,输出的结果秒数,如果将结果乘以1000则输出的为毫秒数.
常量CLOCKS_PER_SEC,它用来表示一秒钟会有多少个时钟计时单元
//而非(double)((finish
- start) / CLOCKS_PER_SEC) &
先会将finish - start转换成double型数据,然后执行&/&操作,则编译器自动将CLOCKS_PER_SEC提升为double型,故而是两个double数据相除
能得到正确结果。
你也可以用clock函数来计算你的机器运行一个循环或者处理其它事件到底花了多少时间。
在标准C/C++中,最小的计时单位是1毫秒。

本文已收录于以下专栏:
相关文章推荐
1.1   用WM_TIMER来设置定时器
先请看SetTimer这个API函数的原型
UINT_PTR   SetTimer(
HWND   hWnd,   //   窗口句柄 ...
1.1   用WM_TIMER来设置定时器 先请看SetTimer这个API函数的原型 UINT_PTR   SetTimer( HWND   hWnd,   //   ...
在高性能的服务器程序当中,定时器是必不可少的部件,而且定时器的效率是直接影响到服务的性能。在众多的开源项目中,定时器设计都有各有各的方法,例如ACE和libEvent都采用了最小堆的算法实现,还有其他...
深入GetMessage和PeekMessage
Bob Gunderson
MSDN技术组
本来想自己写一篇关于boost thread的文章来着,从网上一搜,觉得这篇文章入门最合适了。转自:/janvy/archive//11...
先请看SetTimer这个API函数的原型
#include &stdafx.h&
void CALLBACK TimeProc(HWND hwnd,UINT...
一段关于定时器的程序 // ThunderFind.cpp : 定义控制台应用程序的入口点。
#include &stdafx.h&
转自:/linzuxin@126/blog/static//
 用WM_TIMER来设置定时器 
...
定时器概念:
使用定时器的目的是周期性的执行一个任务,或者是到某一时间去执行某一任务。本章用来处理断开连接超时的客户端,为此,将每个定时时间封装成定时器,并使用链表,时间轮(也是链表),堆等容器类...
他的最新文章
讲师:宋宝华
讲师:何宇健
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)君,已阅读到文档的结尾了呢~~
基于Visual C++6. 0 的Windows应用程序定时器研究
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
基于Visual C++6. 0 的Windows应用程序定时器研究
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口

我要回帖

更多关于 定时器延时函数 的文章

 

随机推荐