7

这个问题不是关于在 Windows(XP 或更好)上准确地计时,而是关于通过回调或中断非常快速地做某事。

我需要每隔 1 毫秒,甚至最好每 100 微秒定期做一些事情。我需要做的是以这种速率驱动一些异步硬件(以太网)以向网络输出稳定的数据包流,并使该流看起来尽可能规则和同步。但是,如果可以将问题与(以太网)设备分开,那么知道一般答案会很好。

在您说“甚至不要考虑使用 Windows !!!!!!”之前,请先了解一下上下文。并非所有实时系统都有相同的需求。尽管需要平均每 10-16 毫秒左右处理一次音频或图像块,但大多数情况下,歌曲和视频在 Windows 上的播放是可以接受的。通过适当的缓冲,Windows 可以有其可变的延迟,但硬件可以大致不受它们的影响,并保持稳定的同步事件流发生。即便如此,我们大多数人都能容忍偶尔出现的故障。我的应用程序就是这样 - 可能非常宽容。

对我来说,昂贵的选择是将我的整个应用程序移植到 Linux。但 Linux 只是在相同硬件上运行的不同软件,所以我强烈倾向于编写一些更好的软件,并坚持使用 Windows。我有幸能够消除所有竞争的硬件和软件(没有互联网或其他网络访问,没有其他应用程序运行等)。我是否有希望让 Windows 做到这一点?我会遇到什么限制?

我知道我的目标硬件有一个高性能事件定时器,并且这个定时器可以被编程为中断,但是没有驱动程序。我可以写一个吗?那里有有用的例子吗?我还没有找到一个。这会干扰 QueryPerformanceCounter 吗?我将使用以太网设备这一事实是否意味着如果我明智地使用 select() 一切都会变得简单?

欢迎提供有用文章的指针——我发现了许多关于如何获得准确时间的概述,但除了使用相当于繁忙等待的情况外,还没有关于如何做这样的事情的概述。有没有办法避免忙碌的等待?是否有内核模式或设备驱动程序选项?

4

4 回答 4

5

您应该考虑查看多媒体计时器。这些计时器旨在满足您正在查看的分辨率。

在MSDN上看看这里。

于 2011-08-10T00:52:42.647 回答
0

我使用 DirectX 9 进行了此操作,使用 . QueryPerformanceCounter,但您需要占用至少一个内核,因为任务切换会搞砸您。

为了对 tiemers 进行很好的比较,您可以查看

http://www.geisswerks.com/ryan/FAQS/timing.html

于 2011-08-10T00:58:01.540 回答
0

如果您遇到计时器粒度问题,我建议您使用带有自旋循环的老式 Sleep()。本质上,代码应该执行以下操作:

void PrecisionSleep(uint64 microSec)
{
    uint64 start_time;

    start_time = GetCurrentTime(); // assuming GetCurrentTime() returns microsecs

    // Calculate number of 10ms intervals using standard OS sleep.
    Sleep(10*(microSec/10000)); // assuming Sleep() takes millisecs as argument

    // Spin loop to spend the rest of the time in
    while(GetCurrentTime() - start_time < microSec)
    {}
}

这样,您将获得高精度睡眠,如果其中很多大于调度粒度(假设为 10 毫秒),则不会对 CPU 造成太大负担。您可以循环发送数据包,同时使用高精度睡眠对它们进行计时。

音频在大多数系统上都能正常工作的原因是音频设备有自己的时钟。您只需将音频数据缓冲到它,它会负责播放它并在缓冲区为空时中断程序。事实上,如果播放引擎依赖于 CPU 时钟,声卡时钟和 CPU 时钟之间的时间偏差可能会导致问题。

编辑:您可以通过使用一个线程来进行计时器抽象,该线程使用一个受锁保护的定时条目最小堆(堆比较在到期时间戳上完成),然后您可以回调()或 SetEvent()当PrecisionSleep() 到下一个时间戳完成。

于 2011-08-10T02:04:14.410 回答
0

程序启动时使用NtSetTimerResolution设置定时器分辨率。是的,它是未记录的功能,但效果很好。您也可以使用NtQueryTimerResolution来了解计时器分辨率(确保在设置新分辨率之前和之后)。

您需要使用GetProcAddressfrom动态获取这些函数的地址NTDLL.DLL,因为它没有在头文件或任何 LIB 文件中声明。

以这种方式设置计时器分辨率会影响SleepWindows 计时器、返回当前时间的函数等。

于 2011-08-11T15:06:49.430 回答