btw:网上的threaded timer控件的功能主要是什么啊?
谢谢
谢谢
解决方案 »
- ******超级猛料2006在线版******
- [求助]:ConnectNamedPipe在Win98下面可以用嗎?
- 如何设置正确设置进度条的步长?
- 客户端连接数为什么不能超过十?
- 如何改变Activeform在浏览器中显示的大小?
- 请问,哪里有比较好的数据库备份与恢复控件。
- Delphi中ADO的问题,头都大了。 换ADO真是失策的哦~!
- 得到计算机名用什么呀?
- 都来看看,这是什么病毒?三百分,解决了马上给分
- 有直接能够把WebBrowser中某个连接或者某个页面直接保存为一个mht文件的接口?
- 各位高手请进:有关Timer的有关问题!
- 用delphi的 TMediaPlayer 怎样实现慢放,快放功能,可以吗?
begin
m:=gettickcount;
sleep(1234);
showmessage(inttostr(gettickcount-m)+' ms')
end;
如果timer的interval小于50ms其准确性就很差了
而我要做的是timer的interval是1mssleep()用的是系统时钟计时还是timer啊?
QueryPerformanceFrequency
QueryPerformanceFrequency
是什么意思阿
能不能说得详细一些那?
如果用buttonclick实现那段代码
sleep(50)的话, message中显示的时间有时是62ms,有时是47ms
作者 : TechnoFantasy
在windows中的很多场合下编程(例如工业控制、游戏)中需要比较精确的记时器,本文讨论的是在delphi下实现记时器的若干方法以及它们的精度控制问题。在delphi中最常用的是timer控件,它的设置和使用都非常方便,理论上它的记时精度可以达到1ms(毫秒)。但是众所周知的,实际上timer在记时间隔小于50ms之下是精度是十分差的。它只适用于对于精度要求不太高的场合。 这里作者要介绍的是两种利用windows api函数实现精确记时的方法。第一中方法是利用高性能频率记数(作者本人的称呼)法。利用这种方法要使用两个api函数queryperformancefrequency和queryperformancecounter。queryperformancefrequency函数获得高性能频率记数器的震荡频率。调用该函数后,函数会将系统频率记数器的震荡频率(每毫秒)保存到一个largeinteger中。不过利用该函数在几台机器上做过试验,结果都是1193180。读者朋友可以在自己的机器上试一下queryperformancecounter函数获得系统频率记数器的震荡次数,结果也保存到一个largenteger中。很显然,如果在计时中首先使用queryperformancefrequency获得高性能频率记数器每毫秒的震荡次数,然后在计时开始时使用queryperformancecounter函数获得当前系统频率记数器的震荡次数。在计时结束时再调用queryperformancecounter函数获得系统频率记数器的震荡次数。将两者相减,再将结果除以频率记数器每毫秒的震荡次数,就可以获得某一事件经过的准确时间。(次数除以频率等于时间)另外的一种精确记时器的功能是利用多媒体记时器函数(这也是作者的定义,因为这个系列的函数是在winmm.dll中定义并且是为媒体播放服务的)。实现多媒体记时器首先要使用timesetevent函数建立计时事件。该函数在delphi中的mmsystem.pas中有定义,定义如下:function timesetevent(udelay, uresolution: uint; lpfunction: tfntimecallback; dwuser: dword; uflags: uint): mmresult; stdcall函数定义中参数udelay定义延迟时间,以毫秒为单位,该参数相当于timer控件的interval属性。参数uresolution定义记时精度,如果要求尽可能高的精度,要将该参数设置为0;参数lpfunction定义了timesetevent函数的回调函数。该函数相当于一个定时中断处理函数,每当经过一个udelay长度的时间间隔,该函数就会被调用,编程者可以在该函数中加入相应的处理语句。参数dwuser定义用户自定义的回调值,该值将传递给回调函数。参数uflags定义定时类型,如果要不间断的记时,该值应设置为1。如果函数调用成功,在系统中建立了一个多媒体记时器对象,每当经过一个udelay时间后lpfunction指定的函数都会被调用。同时函数返回一个对象标识,如果不再需要记时器则必须要使用timekillevent函数删除记时器对象。 由于windows是一个多任务的操作系统,因此基于api调用的记时器的精度都会受到其它很多因素的干扰。到底这两中记时器的精度如何,我们来使用以下的程序进行验证:设置三种记时器(timer控件、高性能频率记数、多媒体记时器)。将它们的定时间隔设置为10毫秒,让它们不停工作直到达到一个比较长的时间(比如60秒),这样记时器的误差会被累计下来,然后同实际经过的时间相比较,就可以得到它们的精度。
从上面的结果看,由delphi的timer控件建立的记时器的精度十分差,无法在实际中使用,而利用高性能频率记数法和多媒体计数器法的误差都在1%以下。考虑到程序中在文本框中显示时间对程序所造成的影响,这个误差在应用中是完全可以忽略的。另外在运行程序时作者还发现一个问题,如果在倒记时时拖动窗口,文本框中的显示都会停止,而当停止窗口拖放后,多媒体记时器显示会跳过这段时间记时,而其它两种记时器显示倒记时却还是从原来的时间倒数。这说明多媒体记时器是在独立的线程中运行的,不会受到程序的影响。综合上面的介绍和范例,我们可以看到,如果要建立高精度的记时器,使用多媒体记时器是比较好的选择。而高性能频率记数法比较适合计算某个耗时十分短的过程所消耗的时间(例如分析程序中某个被多次调用的程序段执行时间以优化程序),因为毕竟高性能频率记数的理论可以达到微秒级别。timer控件虽然精度比上面两者差很多,但是它使用方便,在要求不高的场合它还是最佳选择。(最后要说的是,以上的结果都是在windows 9x下获得的,作者在windows 2000下运行该程序时发现,timer控件的精度比在windows 9x下要高出很多,一般误差在5%以下,这说明windows 2000是一个真正的多任务操作系统。再加上windows nt\2000的稳定性和易用性,在工业控制或实时检测等领域是一个比较完美的平台)
1、首先,每一个TTimer实例都会创建一个窗口,我们知道窗口是会消耗系统资源的,特别是在Win9X下,当用户资源或GDI资源用完时,死机就是不可避免的了。其实只需要一个窗口,根据不同的定时器ID就可区分了。Rxlib中有一个组件叫RxTimerList,它就是只使用了一个窗口句柄和一个定时器ID,通过特别的算法实现多个定时器的功能,不过它的定时精度较低。
2、从表面上看,TTimer的定时分辨率是1ms,Win32 SDK中也没有提及内部定时器精度问题。事实上,很多朋友都知道,Win9X下它的实际分辨率是55ms,而NT/2000下是10ms左右。对TTimer来说,将Interval属性设置为1和55效果是一样的,写一个很简单的程序就可证明(Win9X下)。 很多书上提到Win9X下定时器的实际精度是55ms,事实真的就是这样吗?
我在实测中发现一些有趣的现象(以下描述都在Win98SE下):
1、将定时间隔设为1ms,用一段代码在窗体上显示实际的定时间隔。
2、运行程序,我发现定时间隔在55ms左右,每秒约18次。
3、而当我快速移动鼠标或持续按住某个键时,实际间隔最短变化到20ms左右,每秒可达数十次。
4、当我在程序中加入一段串口通讯代码,并通过外部硬件向串口连续发数时,定时器速度居然达到了数百次。 55ms的定时间隔,让我很容易地联想到Dos下的外部定时中断INT08,再看看键盘中断INT09、串口中断INT0C,很自然地得出这样的结论:
Win9X是在响应外部中断时处理定时器的,正常情况下INT08定时中断的产生频繁最高,所以表现出的实际定时精度为55ms。
为了证明这一想法,我写了一个简单的程序:
* 在窗体上放两个TTimer,定时间隔为55ms,Enabled为假,再放一按钮,四个标签。
* 在定时事件中将GetTickCount(从开机到当前经过的毫秒数)的值显示出来,再将定时器关掉。
* 在按钮事件中先将第一个定时器打开,显示当前时间,用Sleep延时25ms,再将第二个定时器打开,显示当前时间。
执行结果可看到,虽然两个定时器开启的时间相差了27ms,但两个定时事件发生在同一时间段内(显示值完全相同)。达到1ms是不可能的,即使使用线程技术的timer也达不到1ms