Qt high-resolution timer

2019-01-15 04:15发布

I'm writing an emulator for a system with C++, using Qt for UI, event handling, and so on. Obviously, I need to have an accurate timing reference. Right now, I use a QTimer with the appropriate interval (16.66667 ms for NTSC, 20 ms for PAL) but as expected, the accuracy of that is horrible. Sometimes the timer fires at 50 FPS, sometimes 120 FPS.

I realise that most operating systems have some function to provide an accurate timestamp down to the micro- (or nano-) second level. (i.e. QueryPerformanceCounter on Windows.)

Instead of using the system clocks, I was also thinking of synchronising to the audio clock, since I already have an audio output stream, but I don't think Qt offers functionality for that.

What would be the easiest (and/or best) way to synchronise to some accurate clock to call a function at a specific time interval, with little jitter during normal circumstances, from C++/Qt?

标签: qt timer
2条回答
等我变得足够好
2楼-- · 2019-01-15 05:04

QTimer is an event-loop timer. Which mean it only delivers when the even loop is free to process events. It may also skip if the condition is "right".

As far as I know, there's no sure firing timer in Qt. You will have to go with platform-specific calls.

One possible Qt solution may be a thread separate from the main GUI thread that does the counting using msleep or usleep. You can have a timer thread that sleep for some time and wake up, wake another thread that does the actual job with a semaphore then goes back to sleep. The working thread does a slice of job then wait on the semaphore again.

QThread::sleep does not rely on event loop and may have better accuracy.

查看更多
霸刀☆藐视天下
3楼-- · 2019-01-15 05:10

High-resolution timestamps don't mean that there's a mechanism within the kernel that will wake up a sleeping thread when a given value of a high-resolution timestamp has been reached.

On Qt and on Windows, when your timer timeout is "short enough" (<= 10ms IIRC), Qt will force system's tick interval to ~1ms (either 1000Hz or 1024Hz).

What you need to do is as follows:

  1. Keep track of high resolution time using QElapsedTimer (internally it uses performance counters on Windows or whatever is there to give the highest resolution time).

  2. Set the timer expiration based on the value of high resolution time from #1.

Of course you need to handle frames that took too long, timers that were missed, etc. But that's the only sane way to get it to work.

Alternatively, you can use notifications when the audio buffers have drained to a certain level. Qt 5 may provide APIs for that.

The only way you can generate better timing on any operating system is to use specialized hardware other than the general purpose timer tick. Such hardware may be something as simple as a serial port running in the loopback mode. It can be extremely useful as an additional and independent waitable event source. Audio buffer swaps can be a good source of timing, too.

If you wish to further trade off power consumption for timing accuracy, you can dedicate a hyper thread to busy waiting while polling a high resolution time source. This is not something to do lightly, but for certain applications, say for a testing harness, it may be OK. Laptop/notebook/tablet users would hate you for it.

Beware of a fantastic article out there that proposes a solution that has no chance of working, in the absence of real (as opposed to imagined) network card "timers" that would somehow influence socket poll wait.

查看更多
登录 后发表回答