C++ cli 如何(合理地)每N毫秒精确执行一次操作?

C++ cli 如何(合理地)每N毫秒精确执行一次操作?,c++-cli,precision,time-precision,timestamping,C++ Cli,Precision,Time Precision,Timestamping,我有一台机器,它使用NTP客户端同步到互联网时间,所以它的系统时钟应该相当准确 我正在开发一个应用程序,它实时记录数据,处理数据,然后传递数据。我现在想做的是每N毫秒输出一次与系统时钟对齐的数据。例如,如果我想做20毫秒的间隔,我的输出应该是这样的: 13:15:05:000 13:15:05:020 13:15:05:040 13:15:05:060 我已经看到了使用stopwatch类的建议,但是它只测量时间跨度,而不是寻找特定的时间戳。执行此操作的代码在它自己的线程中运行,因此如果我需要

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

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

13:15:05:000
13:15:05:020
13:15:05:040
13:15:05:060
我已经看到了使用stopwatch类的建议,但是它只测量时间跨度,而不是寻找特定的时间戳。执行此操作的代码在它自己的线程中运行,因此如果我需要执行一些相对阻塞的调用,这应该是一个问题


我们将非常感谢您对如何实现这一目标提出的任何建议(接近或优于1ms的精度会更好)。

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

这样:

  • 您可以控制指令计数
  • 您的应用程序将具有执行优先级

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

这样:

  • 您可以控制指令计数
  • 您的应用程序将具有执行优先级

不知道它与C++/CLR的配合有多好,但您可能想看看,

Windows并不是真正的实时操作系统,但它已经非常接近了

不知道它在C++/CLR上的表现如何,但您可能想看看,

Windows并不是真正的实时,但这是最接近的

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

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

最终你无法保证你想要什么,因为操作系统必须满足其他进程的请求才能运行,这意味着,在您希望流程运行的时刻,其他的东西总是很忙。但您可以使用
timeBeginPeriod
改进问题,使您的流程更有可能及时切换到,也许你会巧妙地在迭代之间等待——例如,大部分时间都在睡觉,但不是所有时间都在睡觉,然后在剩下的时间里使用繁忙的循环。

最终你无法保证你想要什么,因为操作系统必须满足其他进程的请求才能运行,这意味着,在您希望流程运行的时刻,其他的东西总是很忙。但是,您可以使用
timeBeginPeriod
来改进问题,使您的流程更有可能被及时切换到,并且可能会巧妙地处理迭代之间的等待方式,例如,大部分时间都处于睡眠状态,但不是所有时间都处于睡眠状态,其余时间则使用繁忙循环。

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

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

因为正如您所说,这并不一定是完美的,有一些事情是可以做到的

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


正如已经指出的,Windows不是实时操作系统。因此,您必须假设,即使您计划在“:0010”处启动计时器,您的代码也可能在该时间之后很久才会执行(例如“:0540”)。只要你妥善处理这些问题,事情就会“好起来”

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

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

正如已经指出的,Windows不是实时操作系统。因此,您必须假设,即使您计划一个计时器在“:0010”处启动,您的代码也可能在该时间之后很久才会执行(例如,”:
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();
}