3

我正在为带有 C++ 的系统编写模拟器,使用 Qt 进行 UI、事件处理等。显然,我需要有一个准确的时间参考。现在,我使用具有适当间隔的 QTimer(NTSC 为 16.66667 毫秒,PAL 为 20 毫秒),但正如预期的那样,其准确性非常糟糕。有时计时器以 50 FPS 的速度触发,有时以 120 FPS 的速度触发。

我意识到大多数操作系统都有一些功能可以提供精确到微(或纳)秒级别的时间戳。(即QueryPerformanceCounter在 Windows 上。)

除了使用系统时钟之外,我还考虑与音频时钟同步,因为我已经有一个音频输出流,但我认为 Qt 没有为此提供功能。

从 C++/Qt 同步到某个准确时钟以在特定时间间隔调用函数的最简单(和/或最佳)方法是什么,在正常情况下几乎没有抖动?

4

2 回答 2

5

高分辨率时间戳并不意味着内核中有一种机制可以在达到高分辨率时间戳的给定值时唤醒休眠线程。

在 Qt 和 Windows 上,当您的计时器超时“足够短”(<= 10ms IIRC)时,Qt 将强制系统的滴答间隔为 ~1ms(1000Hz 或 1024Hz)。

你需要做的如下:

  1. 使用跟踪高分辨率时间QElapsedTimer(在内部它使用 Windows 上的性能计数器或任何提供最高分辨率时间的东西)。

  2. 根据 #1 中的高分辨率时间值设置计时器到期时间。

当然,您需要处理耗时过长的帧、错过的计时器等。但这是让它工作的唯一明智的方法。

或者,您可以在音频缓冲区耗尽到某个级别时使用通知。Qt 5 可能会为此提供 API。

在任何操作系统上生成更好计时的唯一方法是使用除通用计时器滴答之外的专用硬件。这样的硬件可能很简单,例如在环回模式下运行的串行端口。作为一个额外的、独立的可等待事件源,它非常有用。音频缓冲区交换也可以是一个很好的时间来源。

如果您希望进一步权衡功耗以换取计时精度,则可以在轮询高分辨率时间源时将超线程专用于忙于等待。这不是一件容易的事,但对于某些应用程序,比如测试工具,它可能没问题。笔记本电脑/笔记本电脑/平板电脑用户会因此而讨厌你。

当心一篇精彩的文章,该文章提出了一个没有工作机会的解决方案,在没有真实的(与想象的相反)网卡“计时器”会以某种方式影响套接字轮询等待的情况下。

于 2013-09-30T21:13:51.693 回答
0

QTimer 是一个事件循环定时器。这意味着它仅在偶数循环可以自由处理事件时交付。如果条件“正确”,它也可能会跳过。

据我所知,Qt 中没有确定的触发计时器。您将不得不使用特定于平台的调用。

一种可能的 Qt 解决方案可能是与主 GUI 线程分开的线程,该线程使用msleep或进行计数usleep。您可以让定时器线程休眠一段时间并唤醒,唤醒另一个使用信号量执行实际工作的线程,然后重新进入休眠状态。工作线程做了一份工作,然后再次等待信号量。

QThread::sleep不依赖事件循环,可能有更好的准确性。

于 2013-03-31T21:27:42.697 回答