timer如何精确到千分之一秒!
我现在需要做一个网络考试系统(内网)
S发送试卷到C,如果发送的时间超过千分之一秒。那么自动终止发送!
还有就是当C交卷的时候,也需要和上面一样限时! 希望大家可以给我一点思路了!谢谢了!
如果回答好的话,在送100分
我现在需要做一个网络考试系统(内网)
S发送试卷到C,如果发送的时间超过千分之一秒。那么自动终止发送!
还有就是当C交卷的时候,也需要和上面一样限时! 希望大家可以给我一点思路了!谢谢了!
如果回答好的话,在送100分
解决方案 »
- 怎样确定一张很大的图片里面的坐标位置????
- 请大虾帮忙介绍一下vb中的com/activex/ocx/dll/exe的概念!
- vb+水晶报表打包其中应该包含那些水晶报表中的文件呢
- 用Setup Factory 6.0打包后的软件安装过后,运行带有DataGrid的窗体报错?
- 这里有喜欢PASCAL编程和信息学奥赛的朋友吗?
- 第一次作数据库方面的东西 问题:..........
- 在SQL语句中如何让一个字段不显示其它显示,(不一个个写因为字段太多,35个)!!!!
- 如何打补丁--答者有分
- 请问如何枚举当前桌面上已经打开的进程的句柄或ID?(送分300)
- 考考人的问题:不给分,但可以显示拧的实力
- 如何把1串2进制放入到一个16*16的2维数组中
- MCI控件按钮可分开
WINDOWS TIMER最小间隔为52ms.
lowpart As Long
highpart As Long
End TypeDim t1, t2, freq As LARGE_INTEGER
Dim tt As SingleQueryPerformanceFrequency freq
If freq.lowpart < 0 Then freq.lowpart = freq.lowpart + 4294967296#
QueryPerformanceCounter t1
......
QueryPerformanceCounter t1tt = t2.lowpart
tt = tt - t1.lowpart
If tt < 0 Then tt = tt + 4294967296#tt = tt / freq.lowpart 'tt 就是所经历的时间,单位是秒,精度是微秒,分辨率是纳秒。
'取得t1、t2、freq之后不需要任何处理
tt=(t2-t1)*10000.0/freq
您是否有过这样的情况,自己撰写的文章或者论文投稿到一些公开的刊物上去发表,几个月之后却被告知要缴纳所谓的发表费或者版面费或者其他什么费好几百元,现在这些刊物不但不出稿费而是把刊物当成了摇钱树。
本刊《学术之窗》正在申请刊物申请中,预计2008年10第一期出版,省级刊物,月刊。为了保证刊物的顺利和连续性出版,现向各位学者征集稿件,稿件内容不限,2000字左右为宜,文责自负,拒绝盗用、拼凑等类文章。
本刊郑重承诺:
不收取所谓的版面费。
本刊只作为广大学者学术交流的平台,在确定您的文章一定要发表之后,再向您收取30元的刊物成本费用(含邮寄刊物费用)。
投稿邮箱:[email protected]或者[email protected]
等 级:
发表于:2007-11-25 23:43:473楼 得分:10
WINDOWS下不行
WINDOWS TIMER最小间隔为52ms.
真的吗???
如果证明一下
(lpFrequency As LARGE_INTEGER) As Long
函数中的数据结构LARGE_INTEGER定义如下:
Type LARGE_INTEGER
lowpart As Long
highpart As Long
End Type调用该函数后,函数会将系统频率记数器的震荡频率保存到lpPerformanceCount中,其中低位保存到lowpart中,高位保存到highpart中。但是现在的Windows没有使用到hightpart(系统频率记数器的震荡频率与计算机的主频无关,我在几台机上做过验证,都是lowpart为1193180,highpart为0)。
QueryPerformanceCounter函数获得系统频率记数器的震荡次数,函数的定义如下Private Declare Function QueryPerformanceCounter Lib "kernel32" _
(lpPerformanceCount As LARGE_INTEGER) As Long获得记时器震荡次数保存在lpPerformanceCount中。
显然,如果首先获得利用QueryPerformanceFrequency函数获得频率记数器的震荡频率,然后在执行某个程序段之前调用QueryPerformanceCounter函数获得频率记数器的震荡次数,在程序段结束再调用QueryPerformanceCounter函数获得频率记数器的震荡次数,将两次获得的震荡次数相减后再除以震荡频率就获得的了两次间隔之间的时间(以秒为单位)。如果在程序中建立一个循环,在循环中不停的调用QueryPerformanceCounter获得频率记数器的震荡次数并同先前的频率记数器的震荡次数相减,将结果除以频率记数器的震荡频率,如果达到一定的时间就执行某个任务,这样就实现了一个比较精确的记时器的功能。另外的一种精确记时器的功能是利用多媒体记时器函数(这也是作者的定义,因为这个系列的函数是在Winmm.dll中定义并且是为媒体播放服务的)。
实现多媒体记时器首先要定义timeSetEvent函数,该函数的定义如下:Public Declare Function timeSetEvent Lib "winmm.dll" (ByVal uDelay As Long, ByVal _
uResolution As Long, ByVal lpFunction As Long, ByVal dwUser As Long, _
ByVal uFlags As Long) As Long函数定义中参数uDelay定义延迟时间,以毫秒为单位,该参数相当于Timer控件的Interval属性。参数uResolution定义记时精度,如果要求尽可能高的精度,要将该参数设置为0;参数lpFunction定义了timeSetEvent函数的回调函数的地址。参数dwUser定义用户自定义的回调值,该值将传递给回调函数。参数uFlags定义定时类型,如果定义为Time_OneShot,则只会在当达到uDelay定义的时间后调用回调函数一次,如果定义为TIME_PERIODIC,则在每次达到定时时间后调用回调函数。
如果函数调用成功,在系统中建立了一个多媒体记时器对象,每当经过一个uDelay时间后lpFunction指定的函数都会被调用。同时函数返回一个对象标识,如果不再需要记时器则必须要使用timeKillEvent函数删除记时器对象。
由于Windows是一个多任务的操作系统,因此基于API调用的记时器的精度都会受到其它很多因素的干扰。到底这两中记时器的精度如何,我们来使用以下的程序进行验证:
设置三种记时器(Timer控件、高性能频率记数、多媒体记时器)。将它们的定时间隔设置为10毫秒,让它们不停工作直到达到一个比较长的时间(比如60秒),这样记时器的误差会被累计下来,然后同实际经过的时间相比较,就可以得到它们的精度。
下面是具体的检测程序。
首先建立一个工程文件,在Form1中加入一个Timer控件,两个CommandButton控件和三个TextBox控件,然后在Form1的代码窗口中加入以下代码
Option ExplicitPrivate Sub Command1_Click()
Dim lagTick1 As LARGE_INTEGER
Dim lagTick2 As LARGE_INTEGER
Dim lTen As Long
Command2.Enabled = True
Command1.Enabled = False
iCountStart = 60
lmmCount = 60
TimerCount = 60
actTime1 = GetTickCount
lTimeID = timeSetEvent(10, 0, AddressOf TimeProc, 1, 1)
Timer1.Enabled = True
lTen = 10 * lMSFreq
Call QueryPerformanceCounter(lagTick1)
lagTick2 = lagTick1
While iCountStart > 0
Call QueryPerformanceCounter(lagTick2)
'如果时钟震动次数超过10毫秒的次数则刷新Text1的显示
If lagTick2.lowpart - lagTick1.lowpart > lTen Then
lagTick1 = lagTick2
iCountStart = iCountStart - 0.01
Text1.Text = Format$(iCountStart, "00.00")
End If
DoEvents
Wend
End SubPrivate Sub Command2_Click()
EndCount
End SubPrivate Sub Form_Load()
Dim lim As LARGE_INTEGER
Text1.Text = "60.00"
Text2.Text = "60.00"
Text3.Text = "60.00"
Command1.Caption = "开始倒记时"
Command2.Caption = "停止记时"
Command2.Enabled = False
'获得系统板上时钟频率
QueryPerformanceFrequency lim
'将频率除以1000就的出时钟1毫秒震动的次数
lMSFreq = (lim.highpart * 2 ^ 16) \ 1000 + lim.lowpart \ 1000
Timer1.Interval = 10
Timer1.Enabled = False
End SubPrivate Sub Timer1_Timer()
TimerCount = TimerCount - 0.01
Text3.Text = Format$(TimerCount, "00.00")
If TimerCount <= 0 Then
Timer1.Enabled = False
End If
End Sub
在Project中加入一个Module,然后在其中加入以下代码:
Option ExplicitType LARGE_INTEGER
lowpart As Long
highpart As Long
End TypePublic Declare Function QueryPerformanceCounter Lib "kernel32" _
(lpPerformanceCount As LARGE_INTEGER) As Long
Public Declare Function QueryPerformanceFrequency Lib "kernel32" _
(lpFrequency As LARGE_INTEGER) As Long
Public Declare Function timeSetEvent Lib "winmm.dll" (ByVal uDelay As Long, ByVal _
uResolution As Long, ByVal lpFunction As Long, ByVal dwUser As Long, _
ByVal uFlags As Long) As Long
Public Declare Function timeKillEvent Lib "winmm.dll" (ByVal uID As Long) As Long
Public Declare Function GetTickCount Lib "kernel32" () As LongPublic lMSFreq As Long
Public TimerCount As Single
Public lmmCount As Single
Public lTimeID As Long
Public actTime1 As Long
Public actTime2 As Long
Public iCountStart As SingleDim iCount As Single'timeSetEvent的回调函数
Sub TimeProc(ByVal uID As Long, ByVal uMsg As Long, ByVal dwUser As Long, _
ByVal dw1 As Long, ByVal dw2 As Long)
Form1.Text2.Text = Format$(lmmCount, "00.00")
lmmCount = lmmCount - 0.01
If lmmCount <= 0 Then
iCountStart = 60
lmmCount = 60
TimerCount = 60
EndCount
End If
End Sub
Sub EndCount()
iCount = iCountStart
iCountStart = 0
timeKillEvent lTimeID
actTime2 = GetTickCount - actTime1
With Form1
.Command1.Enabled = True
.Command2.Enabled = False
.Timer1.Enabled = False
.Text1 = "计数器记时" + Format$((60 - iCount), "00.00") + " " _
+ "实际经过时间" + Format$((actTime2 / 1000), "00.00")
.Text2 = "计数器记时" + Format$((60 - lmmCount), "00.00") + " " _
+ "实际经过时间" + Format$((actTime2 / 1000), "00.00")
.Text3 = "计数器记时" + Format$((60 - TimerCount), "00.00") + " " _
+ "实际经过时间" + Format$((actTime2 / 1000), "00.00")
End With
End Sub
运行程序,点击“开始倒记时”按钮开始倒记时,可以看到两种API记时器工作基本正常,文本框中的倒记时显示流畅,而Timer控件的时间显示相比之下却不堪重负,十分缓慢。按“停止记时”按钮就可以停止倒记时,由图1可以看到,两种API记时器的累计误差在2‰以下,考虑到系统原因和处理记时显示的时间,这个误差基本是可以接受的,而且经过作者的多次检测,误差都在3‰以下。而Timer控件的误差简直是无法接受的。在运行程序时作者还发现一个问题,如果在倒记时时拖动窗口,文本框中的显示都会停止,而当停止窗口拖放后,多媒体记时器显示会跳过这段时间记时,而其它两种记时器显示倒记时却还是从原来的时间倒数。这说明多媒体记时器是在独立的线程中运行的,不会受到程序的影响。
综合上面的介绍和范例,我们可以看到,如果要建立高精度的记时器,使用多媒体记时器是比较好的选择。而高性能频率记数法比较适合计算某个耗时十分短的过程所消耗的时间(例如分析程序中某个被多次调用的程序段执行时间以优化程序),因为毕竟高性能频率记数的理论可以达到微秒级别。Timer控件虽然精度比上面两者差很多,但是它使用方便,在要求不高的场合它还是最佳选择。
以上程序在Windows 98中文版,VB6下运行通过。
以上代码保存于: SourceCode Explorer(源代码数据库)
复制时间: 2007-11-29 20:21:44
软件版本: 1.0.882
软件作者: Shawls
E-Mail: [email protected]
QQ: 9181729
var
NowCounter,
EndCounter: Int64;
begin
if MilliSeconds < 1 then
begin
Exit;
end;
QueryPerformanceCounter(NowCounter); //------------------------------------------------------------------------------
// 减小Sleep(1)造成的最小误差
//------------------------------------------------------------------------------
EndCounter := NowCounter + MilliSeconds*G_MilliSecondCount;
EndCounter := EndCounter - G_MilliSecondCount shr 1;
while (NowCounter < EndCounter) or (NowCounter < G_StartPerformanceCount) do
begin
Sleep(1);
QueryPerformanceCounter(NowCounter);
end;
end;