我怎样才能(合理地)精确地每 N 毫秒执行一个动作?
-
22-09-2019 - |
题
我有一台机器,它使用 NTP 客户端来同步互联网时间,因此它的系统时钟应该相当准确。
我正在开发一个应用程序,它实时记录数据、处理数据然后传递它。我现在想做的是每 N 毫秒输出与系统时钟一致的数据。例如,如果我想做 20 毫秒的间隔,我的输出应该是这样的:
13:15:05:000
13:15:05:020
13:15:05:040
13:15:05:060
我已经看到了使用秒表类的建议,但它只测量时间跨度,而不是寻找特定的时间戳。执行此操作的代码在它自己的线程中运行,因此如果我需要执行一些相对阻塞的调用,那么这应该是一个问题。
任何关于如何合理地实现这一目标(接近或优于 1 毫秒的精度就更好了)的建议将非常感激。
解决方案
不知道它起着如何用C ++ / CLR,但你可能想看看的多媒体计时器,点击 Windows不是真正实时的,但这是接近,因为它得到
其他提示
您可以得到一个相当准确的时间标记出timeGetTime()时,你缩短了时间。你只需要一些工作来获取其返回值转换为一个时钟时间。此示例C#代码所示的方法:
using System;
using System.Runtime.InteropServices;
class Program {
static void Main(string[] args) {
timeBeginPeriod(1);
uint tick0 = timeGetTime();
var startDate = DateTime.Now;
uint tick1 = tick0;
for (int ix = 0; ix < 20; ++ix) {
uint tick2 = 0;
do { // Burn 20 msec
tick2 = timeGetTime();
} while (tick2 - tick1 < 20);
var currDate = startDate.Add(new TimeSpan((tick2 - tick0) * 10000));
Console.WriteLine(currDate.ToString("HH:mm:ss:ffff"));
tick1 = tick2;
}
timeEndPeriod(1);
Console.ReadLine();
}
[DllImport("winmm.dll")]
private static extern int timeBeginPeriod(int period);
[DllImport("winmm.dll")]
private static extern int timeEndPeriod(int period);
[DllImport("winmm.dll")]
private static extern uint timeGetTime();
}
在第二个想法,这仅仅是测量。为了得到定期执行的操作,你将不得不使用的timeSetEvent()。只要你使用timeBeginPeriod(),就可以得到回调周期非常接近1毫秒。一个精密的是,当先前的回调迟到了任何原因,它将会自动补偿。
最好的选择是使用内联汇编并将这段代码编写为设备驱动程序。
那样:
- 您可以控制指令数量
- 您的应用程序将具有执行优先权
最后你不能保证你想要的,因为操作系统必须从其他进程运行荣誉的请求,这意味着别的东西可以永远忙正是你希望你的程序在运行的时刻。例如 - 但是你可以使用timeBeginPeriod
,使之更可能是你的过程可以及时切换到,也许是狡猾与您如何等待迭代之间改善的问题。睡大多数但不是所有的时间,然后用一个忙环为剩余部分。
尝试在两个线程这样做。在一个线程中,使用类似这查询在一个循环高精度的定时器。当你发现一个时间戳对齐(或合理地接近)20ms的边界,将信号发送到您的日志输出线与时间戳一起使用。你的日志输出线程只会等待信号,然后抓住传入的时间戳和任何需要的输出。保持两个单独的线程将确保您的日志输出线程不与定时器干扰(这基本上是模仿一个硬件定时器中断,这将是我会做一个嵌入式平台上的样子)。
CreateWaitableTimer / SetWaitableTimer和高优先级的线程应精确到1ms左右。我不知道为什么在您的示例输出的毫秒字段具有四位,最大值为999(因为1000毫秒= 1秒)。
既然如你所说,这并不一定是完美的,也有一些事情可以做。
据我所知,不存在一个计时器,与特定的时间同步。所以,你必须计算你的下一个时间,安排在特定时间的计时器。如果你的计时器只有增量的支持,那么,很容易计算,但因为你可以很容易断的时间之间的CPU被踢增加了更多的错误,你计算你三角洲和定时器输入到内核的时间。
前面已经指出的那样,Windows不是一个实时操作系统。所以,你必须假设,即使你安排一个计时器在到下车“:0010”,你的代码可能甚至不执行,直到那个时候好后(例如“:0540”)。只要你正确地处理这些问题,事情就会“OK”。
20ms的是大约Windows上的时间片的长度。有没有办法打1ms的那种定时在windows可靠没有某种RT的增加像银泰。在windows正确,我认为你的选择是WaitForSingleObject的,SleepEx和繁忙的循环。