我怎样才能(合理地)每N毫秒精确地执行一次动作?

我有一台机器使用NTP客户端同步到互联网时间,因此它的系统时钟应该相当准确。 我有一个我正在开发的应用程序,它实时记录数据,处理它然后传递它。我现在要做的是输出数据每N毫秒与系统时钟对齐。所以,例如,如果我想做20ms的间隔,我的oututs应该是这样的:
13:15:05:000
13:15:05:020
13:15:05:040
13:15:05:060
我已经看到了使用秒表类的建议,但这只是测量时间跨度而不是寻找特定的时间戳。执行此操作的代码在其自己的线程中运行,因此如果我需要执行一些相对阻塞的调用应该是一个问题。 任何关于如何实现这一目标的建议(接近或优于1ms的精度都会很好)将非常感激地收到。     
已邀请:
不知道它与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”)。只要你正确处理这些问题,事情就会“好”。     
20ms大约是Windows上时间片的长度。如果没有像银泰这样的RT添加,就无法在Windows中可靠地达到1ms的时序。在Windows中,我认为您的选项是WaitForSingleObject,SleepEx和繁忙的循环。     

要回复问题请先登录注册