1

我有一台使用 NTP 客户端同步到互联网时间的机器,因此它的系统时钟应该相当准确。

我有一个正在开发的应用程序,它实时记录数据,处理它然后传递它。我现在想做的是每 N 毫秒输出一次与系统时钟对齐的数据。因此,例如,如果我想做 20 毫秒的间隔,我的输出应该是这样的:

13:15:05:000
13:15:05:020
13:15:05:040
13:15:05:060

我已经看到了使用秒表类的建议,但它只测量时间跨度,而不是寻找特定的时间戳。执行此操作的代码在它自己的线程中运行,所以如果我需要做一些相对阻塞的调用应该是个问题。

任何关于如何以合理的方式实现这一点的建议(接近或优于 1ms 的精度会很好)将非常感激地收到。

4

8 回答 8

2

不知道它在 C++/CLR 上的表现如何,但你可能想看看多媒体计时器
Windows 不是真正的实时的,但这已经很接近了

于 2010-03-25T17:18:37.980 回答
2

当您减少时间段时,您可以从 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 毫秒的回调周期。一个好处是它会在前一个回调因任何原因迟到时自动补偿。

于 2010-03-25T18:18:25.343 回答
1

最终,您无法保证您想要什么,因为操作系统必须遵守来自其他进程的请求才能运行,这意味着在您希望进程运行的那一刻,其他东西总是很忙。但是您可以改进问题,timeBeginPeriod以使您的流程更有可能及时切换,并且可能对您在迭代之间的等待方式很狡猾 - 例如。大部分时间但不是所有时间都在睡觉,然后在其余时间使用繁忙循环。

于 2010-03-25T17:28:12.500 回答
1

尝试在两个线程中执行此操作。在一个线程中,使用类似这样的方法在循环中查询高精度计时器。当您检测到与 20 毫秒边界对齐(或相当接近)的时间戳时,请向您的日志输出线程发送一个信号以及要使用的时间戳。您的日志输出线程将简单地等待一个信号,然后获取传入的时间戳并输出所需的任何内容。将这两个线程保持在单独的线程中将确保您的日志输出线程不会干扰计时器(这实质上是模拟硬件计时器中断,这将是我在嵌入式平台上执行的方式)。

于 2010-03-25T17:29:09.683 回答
1

您最好的选择是使用内联汇编并将这段代码编写为设备驱动程序。

那样:

  • 您可以控制指令数
  • 您的应用程序将具有执行优先级
于 2010-03-25T17:16:47.763 回答
0

CreateWaitableTimer/SetWaitableTimer 和高优先级线程应该精确到 1ms 左右。我不知道为什么您的示例输出中的毫秒字段有四位数字,最大值是 999(因为 1000 毫秒 = 1 秒)。

于 2010-03-25T17:25:55.237 回答
0

20ms 大约是 Windows 上时间片的长度。如果没有像 Intime 这样的 RT 插件,就无法在 Windows 中可靠地达到 1ms 的时间。在 Windows 中,我认为您的选项是 WaitForSingleObject、SleepEx 和繁忙循环。

于 2010-03-25T17:36:24.380 回答
0

正如你所说,这不一定是完美的,有一些事情可以做。

据我所知,不存在与特定时间同步的计时器。因此,您将不得不计算您的下一次时间并为该特定时间安排计时器。如果您的计时器仅支持增量,那么这很容易计算,但会增加更多错误,因为在计算增量和计时器进入内核的时间之间,您很容易被 CPU 踢掉。

正如已经指出的,Windows 不是实时操作系统。所以你必须假设即使你安排一个定时器在“:0010”下车,你的代码甚至可能直到那个时间之后才执行(例如,“:0540”)。只要你妥善处理这些问题,一切都会“好”。

于 2010-03-25T17:30:20.547 回答