Qt高分辨率定时器

3
我正在使用C++和Qt构建一个系统仿真器,用于UI、事件处理等方面。显然,我需要一个准确的时间参考。目前,我使用适当间隔(NTSC为16.66667毫秒,PAL为20毫秒)的QTimer,但正如预期的那样,其精度非常差。有时计时器以50FPS触发,有时以120FPS触发。
我知道大多数操作系统都有一些函数可以提供准确到微(或纳)秒级别的时间戳。(例如Windows上的QueryPerformanceCounter)。
除了使用系统钟表外,我还考虑过同步音频时钟,因为我已经有一个音频输出流,但我不认为Qt提供这样的功能。
从C++/Qt中,最容易(和/或最佳)的方法是什么,可以同步到某个准确的时钟,在正常情况下具有较少的抖动,并在特定时间间隔内调用函数?
2个回答

5
高分辨率时间戳并不意味着内核中有一种机制,可以在达到高分辨率时间戳的特定值时唤醒正在睡眠的线程。
在Qt和Windows上,当计时器超时“足够短”(<= 10ms IIRC)时,Qt将强制系统的滴答间隔为~1ms(1000Hz或1024Hz)。
您需要执行以下操作:
1.使用QElapsedTimer跟踪高分辨率时间(在Windows上内部使用性能计数器或任何可用的方式提供最高分辨率时间)。
2.根据#1中的高分辨率时间设置计时器过期。
当然,您需要处理花费过长的帧,错过的计时器等。但这是使其正常工作的唯一合理方法。
或者,您可以在音频缓冲区排空到某个水平时使用通知。 Qt 5可能提供此类API。
唯一能在任何操作系统上生成更好的时间精度的方法是使用专用硬件而非通用定时器滴答声。这种硬件可能只是运行在环回模式下的串口。它可以作为附加和独立的可等待事件源非常有用。音频缓冲区交换也可以成为一个很好的时间来源。
如果你希望进一步以时间精度为代价来换取功耗,你可以将一个超线程专用于忙等待,同时轮询高分辨率时间源。这不是轻易可以做的事情,但对于某些应用程序,比如测试工具,可能还可以接受。笔记本电脑/平板电脑用户会讨厌你这样做。
要小心那些提出一个没有机会实现的解决方案的奇妙文章,在缺乏真实(而非想象中的)网络卡“定时器”影响套接字轮询等待的情况下,这是无法实现的。

0

QTimer是一个事件循环定时器,意味着只有当事件循环空闲时才会触发。如果条件“正确”,它也可能会跳过。

据我所知,在Qt中没有可以确保触发的定时器。您必须使用特定于平台的调用。

一个可能的Qt解决方案是创建一个与主GUI线程分离的线程,使用msleepusleep进行计数。您可以有一个定时器线程休眠一段时间,然后唤醒另一个线程,该线程使用信号量执行实际工作,然后再次进入休眠状态。工作线程完成一部分工作后,再次等待信号量。

QThread::sleep不依赖于事件循环,可能具有更高的精度。


3
这个回答属于传闻。在Qt中,计时器的触发与底层操作系统提供的计时器一样好,不会更差。没有什么神奇的调用可以使事情变得更好。在Windows上,usleepmsleep具有相同的默认分辨率:15毫秒。当您使用短超时时间触发计时器时,Qt将全局窗口计时器间隔切换为1毫秒,以换取计时器准确性而牺牲功耗。不存在所谓的“事件循环”。每个线程都有自己的事件循环。没有人强制您在GUI事件循环中运行计时器,可以在单独的高优先级线程中运行它们。 - Kuba hasn't forgotten Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接