I need an accurate timer to interface a Windows application to a piece of lab equipment.
我需要一个准确的计时器来将Windows应用程序连接到一个实验室设备。
I used System.Timers.Timer() to create a timer that ticks every 10 msec, but this clock runs slow. For example 1000 ticks with an interval of 10 msec should take 10 wall-clock seconds, but it actually takes more like 20 wall-clock sec (on my PC). I am guessing this is because System.Timers.Timer() is an interval timer that is reset every time it elapses. Since it will always take some time between when the timer elapses and when it is reset (to another 10msec) the clock will run slow. This probably fine if the interval is large (seconds or minutes) but unacceptable for very short intervals.
我使用System.Timers.Timer()来创建一个每10毫秒滴答一次的计时器,但这个时钟运行缓慢。例如,间隔为10毫秒的1000个刻度应该需要10个挂钟秒,但它实际上需要20个挂钟(在我的电脑上)。我猜这是因为System.Timers.Timer()是一个间隔计时器,每次经过时都会重置。由于在定时器过去和重置之间(另一个10毫秒)之间总是需要一些时间,因此时钟将运行缓慢。如果间隔很大(几秒或几分钟),这可能很好,但是对于非常短的间隔是不可接受的。
Is there a function on Windows that will trigger a procedure every time the system clock crosses a 10 msec (or whatever) boundary?
Windows上是否有一个函数会在每次系统时钟超过10毫秒(或其他)边界时触发一个过程?
This is a simple console application.
这是一个简单的控制台应用程序
Thanks
Norm
UPDATE: System.Timers.Timer() is extremely inaccurate for small intervals.
更新:System.Timers.Timer()对于小间隔非常不准确。
I wrote a simple program that counted 10 seconds several ways:
我写了一个简单的程序,计算10秒:
Interval=1, Count=10000, Run time = 160 sec, msec per interval=16
间隔= 1,计数= 10000,运行时间= 160秒,每间隔msec = 16
Interval=10, Count=1000, Run time = 16 sec, msec per interval=15
间隔= 10,计数= 1000,运行时间= 16秒,每间隔毫秒= 15
Interval=100, Count=100, Run time = 11 sec, msec per interval=110
间隔= 100,计数= 100,运行时间= 11秒,每间隔msec = 110
Interval=1000, Count=10, Run time = 10 sec, msec per interval=1000
间隔= 1000,计数= 10,运行时间= 10秒,每间隔msec = 1000
It seems like System.Timers.Timer() cannot tick faster that about 15 msec, regardless of the interval setting.
无论间隔设置如何,似乎System.Timers.Timer()无法在15毫秒内快速打勾。
Note that none of these tests seemed to use any measurable CPU time, so the limit is not the CPU, just a .net limitation (bug?)
请注意,这些测试似乎都没有使用任何可测量的CPU时间,因此限制不是CPU,只是.net限制(bug?)
For now I think I can live with an inaccurate timer that triggers a routine every 15 msec or so and the routine gets an accurate system time. Kinda strange, but...
现在我认为我可以使用一个不准确的计时器,每15毫秒左右触发一个程序,并且例程可以获得准确的系统时间。有点奇怪,但......
I also found a shareware product ZylTimer.NET that claims to be a much more accurate .net timer (resolution of 1-2 msec). This may be what I need. If there is one product there are likely others.
我还发现了一个共享软件产品ZylTimer.NET,它声称是一个更精确的.net计时器(分辨率为1-2毫秒)。这可能是我需要的。如果有一种产品,可能还有其他产品。
Thanks again.
6 个解决方案
#1
You need to use a high resolution timer such as QueryPerformanceCounter
您需要使用高分辨率计时器,例如QueryPerformanceCounter
#2
On surface of it the answer is something like "high resolution timer" however this is incorrect. The answer requires a regular tick generation and the windows high res performance counter API does not generate such a tick.
在表面上,答案就像“高分辨率计时器”,但这是不正确的。答案需要定期生成滴答,并且windows高分辨率性能计数器API不会产生这样的滴答。
I know this is not answer inself but the popular answer to this question so far is wrong enough for me to feel that a simple comment on it is not enough.
我知道这不是自己的答案,但到目前为止对这个问题的流行答案是错误的,我觉得对它的简单评论是不够的。
#4
The limitation is given by the systems heartbeat. This typically defaults to 64 beats/s which is 15.625 ms. However there are ways to modify these system wide settings to achieve timer resolutions down to 1 ms or even to 0.5 ms on newer platforms:
系统心跳给出了限制。这通常默认为64次/秒,即15.625毫秒。但是,有一些方法可以修改这些系统范围的设置,以便在较新的平台上实现低至1毫秒甚至0.5毫秒的定时器分辨率:
-
Going for 1 ms resolution by means of the multimedia timer interface (
timeBeginPeriod()
):通过多媒体计时器接口(timeBeginPeriod())获得1 ms的分辨率:
See Obtaining and Setting Timer Resolution.
请参阅获取和设置定时器分辨率。
-
Going to 0.5 ms resolution by means of
NtSetTimerResolution()
:通过NtSetTimerResolution()获得0.5 ms的分辨率:
See Inside Windows NT High Resolution Timers.
请参阅内部Windows NT高分辨率计时器。
You may obtain 0.5 ms resolution by means of the hidden API NtSetTimerResolution()
.
您可以通过隐藏的API NtSetTimerResolution()获得0.5 ms的分辨率。
I've given all the details in this SO answer.
我已经在这个SO答案中给出了所有细节。
#5
Off the top of my head, I could suggest running a thread that mostly sleeps, but when it wakes, it checks a running QueryPerformanceCounter
and occasionally triggers your procedure.
在我的头脑中,我可以建议运行一个主要睡眠的线程,但是当它醒来时,它会检查正在运行的QueryPerformanceCounter并偶尔触发你的程序。
#6
There's a nice write up at the MSDN: Implement a Continuously Updating, High-Resolution Time Provider for Windows
在MSDN上有一个很好的写作:为Windows实现一个连续更新,高分辨率的时间提供程序
Here's the sample source code for the article (C++).
这是文章(C ++)的示例源代码。
#1
You need to use a high resolution timer such as QueryPerformanceCounter
您需要使用高分辨率计时器,例如QueryPerformanceCounter
#2
On surface of it the answer is something like "high resolution timer" however this is incorrect. The answer requires a regular tick generation and the windows high res performance counter API does not generate such a tick.
在表面上,答案就像“高分辨率计时器”,但这是不正确的。答案需要定期生成滴答,并且windows高分辨率性能计数器API不会产生这样的滴答。
I know this is not answer inself but the popular answer to this question so far is wrong enough for me to feel that a simple comment on it is not enough.
我知道这不是自己的答案,但到目前为止对这个问题的流行答案是错误的,我觉得对它的简单评论是不够的。
#3
In System.Diagnostics, you can use the Stopwatch class.
在System.Diagnostics中,您可以使用Stopwatch类。
#4
The limitation is given by the systems heartbeat. This typically defaults to 64 beats/s which is 15.625 ms. However there are ways to modify these system wide settings to achieve timer resolutions down to 1 ms or even to 0.5 ms on newer platforms:
系统心跳给出了限制。这通常默认为64次/秒,即15.625毫秒。但是,有一些方法可以修改这些系统范围的设置,以便在较新的平台上实现低至1毫秒甚至0.5毫秒的定时器分辨率:
-
Going for 1 ms resolution by means of the multimedia timer interface (
timeBeginPeriod()
):通过多媒体计时器接口(timeBeginPeriod())获得1 ms的分辨率:
See Obtaining and Setting Timer Resolution.
请参阅获取和设置定时器分辨率。
-
Going to 0.5 ms resolution by means of
NtSetTimerResolution()
:通过NtSetTimerResolution()获得0.5 ms的分辨率:
See Inside Windows NT High Resolution Timers.
请参阅内部Windows NT高分辨率计时器。
You may obtain 0.5 ms resolution by means of the hidden API NtSetTimerResolution()
.
您可以通过隐藏的API NtSetTimerResolution()获得0.5 ms的分辨率。
I've given all the details in this SO answer.
我已经在这个SO答案中给出了所有细节。
#5
Off the top of my head, I could suggest running a thread that mostly sleeps, but when it wakes, it checks a running QueryPerformanceCounter
and occasionally triggers your procedure.
在我的头脑中,我可以建议运行一个主要睡眠的线程,但是当它醒来时,它会检查正在运行的QueryPerformanceCounter并偶尔触发你的程序。
#6
There's a nice write up at the MSDN: Implement a Continuously Updating, High-Resolution Time Provider for Windows
在MSDN上有一个很好的写作:为Windows实现一个连续更新,高分辨率的时间提供程序
Here's the sample source code for the article (C++).
这是文章(C ++)的示例源代码。