这个问题不是关于在Windows(XP或更高版本)上准确计时,而是通过回调或中断非常快速地做某事。
我需要每隔1毫秒定期做一些事情,或者最好每100微秒做一次。我需要做的是以这个速率驱动一些同步硬件(以太网),以便向网络输出稳定的数据包流,并使该流看起来尽可能规则和同步。但如果问题可以与(以太网)设备分开,那么了解一般答案会很好。
在您说“甚至不考虑使用Windows !!!!”之前,有点背景。并非所有实时系统都有相同的要求。大多数时候歌曲和视频在Windows上可以接受,尽管平均每10-16ms左右需要处理音频或图像块。通过适当的缓冲,Windows可以具有可变的延迟,但硬件可以广泛地免受它们的影响,并保持稳定的同步事件流。即便如此,我们大多数人都容忍偶尔的故障。我的应用程序就是这样 - 可能非常宽容。
对我来说,昂贵的选择是将我的整个应用程序移植到Linux。但Linux只是在同一硬件上运行的不同软件,所以我强烈倾向于编写一些更好的软件,并坚持使用Windows。我能够消除所有竞争的硬件和软件(没有互联网或其他网络访问,没有运行其他应用程序等)。我有可能让Windows这样做吗?我会遇到什么限制?
我知道我的目标硬件有一个高性能事件定时器,并且该定时器可以编程为中断,但没有驱动程序。我可以写一个吗?那里有有用的例子吗?我还没找到一个。这会干扰QueryPerformanceCounter吗?我是否会使用以太网设备这一事实是否意味着如果我明智地使用select()会变得简单?
对有用文章的指示表示欢迎 - 我已经找到了关于如何获得准确时间的几十个概述,但是除了使用等于忙碌的等待之外,还没有关于如何做这样的事情的概述。 有没有办法避免忙碌的等待?是否有内核模式或设备驱动程序选项?
答案 0 :(得分:5)
您应该考虑查看多媒体计时器。这些定时器旨在达到您正在考虑的那种分辨率。
请点击此处MSDN。
答案 1 :(得分:0)
我是使用DirectX 9,使用QueryPerformanceCounter
完成此操作,但是您需要至少使用一个核心,因为任务切换会让您感到困惑。
为了对结合者进行比较,你可以看看
答案 2 :(得分: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)
{}
}
这样,你将拥有一个高精度的睡眠,如果它们中的很多都大于调度粒度(假设为10ms),那么它就不会对你的CPU造成太大的负担。您可以在使用高精度睡眠计时循环发送数据包。
音频在大多数系统上工作正常的原因是音频设备有自己的时钟。您只需将音频数据缓冲到它,它就会播放它并在缓冲区为空时中断程序。实际上,如果播放引擎依赖于CPU时钟,则音频卡时钟和CPU时钟之间的时间偏差会导致问题。
编辑: 您可以通过使用一个使用锁定保护的最小定时条目堆(在比较时间戳上完成堆比较)的线程来进行计时器抽象,然后在PrecisionSleep(可以使用callback()或SetEvent()时)到下一个时间戳完成。
答案 3 :(得分:0)
程序启动时使用NtSetTimerResolution来设置定时器分辨率。是的,它是无证的功能,但效果很好。您也可以使用NtQueryTimerResolution了解计时器分辨率(在设置之前和设置新分辨率之后确定)。
您需要使用GetProcAddress
中的NTDLL.DLL
动态获取这些函数的地址,因为它未在标头或任何LIB文件中声明。
以这种方式设置计时器分辨率会影响Sleep
,Windows计时器,返回当前时间的函数等。