PDA

View Full Version : QTimer behavior when timer processing length goes beyond timer interval



andariel
3rd September 2014, 14:37
Hello,

I would like to understand how internally Qt triggers its QTimer "trigger" event. I'm on a Windows 7 platform (this may be important as timer implementation vaies from one platform to another).
I need to figure out what will happen in case the processing inside the QTimer slot is too long for the selected interval. As an example:



QTimer timer;

timer.setTimerType(Qt::PreciseTimer);
connect(&timer, SIGNAL(timeout()), this, SLOT(_processing()));
timer.start(1000);




void MyClass:_processing(void)
{
int timeout = 2000; // in msec
int result = read(Io_handle, &buffer, timeout);
}


If the IO read succeeds, the processing time will be below one second, which is the QTimer interval, and therefore we didn't "miss" a QTimer event.
On the other side, if the read() goes in timeout, as the timeout is longer than the QTimer interval, what will happen from Qt point of view ?

Qt spec says that:
"All timer types may time out later than expected if the system is busy or unable to provide the requested accuracy. In such a case of timeout overrun, Qt will emit activated() only once, even if multiple timeouts have expired, and then will resume the original interval."

It is true that timer times out later, but it doesn't seem to be true that activated() is emitted only once, and that the original interval is resumed...

In your experience, did you actually see the Preicse Timer behaving as explained above ?
On my side I see some strange behavior with a code similar to the one above: it behaves as if activated() events were "queued", and after exiting a processing that exceeds timer interval, I can see sometimes many timer events executed in a row with no respect at all of the interval, but instead executed ASAP. Sorry, I can't post a working code for the moment because this is part of a large project.

Thanks in advance !

wysota
3rd September 2014, 14:43
You should never rely that the timer will be triggered exactly as many times as many intervals have passed since activating the timer. In other words QTimer is not a proper approach to count time. The only guarantee you get is that the timer will eventually fire and that it will not fire before the given interval passes by. So if you have an interval of 1000 ms and 10 seconds passes by, the timer might fire 10 times but it may fire once.

andariel
3rd September 2014, 16:29
Hello wysota,

thanks for your reply.

In the case where as you said: "the timer might fire 10 times but it may fire once", if it actually fires only once, my understanding is that there isn't 9 QTimer timeout events waiting to happen.
Instead, after the single slot call, the timer is simply restarted with the same interval. Therefore, for one given timer, there is always only one QTimer timeout event (or zero) waiting to be executed. Am I correct ?

Brandybuck
3rd September 2014, 16:42
If I understand your question, you are asking if you have a timer with a one second timeout, and the slot it is connected to takes two seconds to perform, what happens? Will you end up with two timeout signals or just one?

I believe that multiple pending timeouts will be "compressed" into one timeout. (I have not tried this to verify, but I have had projects with similar concerns in the past). This is due to how QTimer works. Timeouts are actually events that get handled in the event loop. For every loop the dispatcher will check all timers to see if any have timed out. It doesn't matter how overdue a timer is, only one timeout will be sent.

If you have a slot that is taking more time than the timeout, that sounds like a design problem. Perhaps the slot should be running in a different thread, perhaps the slot needs to be split up or reorganized, or perhaps a QTimer is not the right solution.

andariel
4th September 2014, 07:13
Hello Brandybuck,

thanks also for your help.
I tend to agree with you because first, this is compatible with the definition given by Qt that says that basically the timer should simply be restarted after timeout even though it timed out with a lot of delay. Also, I did some simple prototypes to evaluate the timer behavior and it behaves as we said.

That said, my problem still persists and unfortunately I can't find a simple example putting it in evidence. I'm having from time to time several execution of the timer slot in a row without any respect of the interval between each timer call, but rather calls done "ASAP". This usually happens after one call has taken too much time. But as I said, trying to demonstrate this with a simple prototype doesn't show any irregularity, so I have a problem elsewhere but I don't know where.

Anyways with my tests and people's answers here at least I believe I'm now convinced of how a QTimer should behave ! :)

wysota
4th September 2014, 07:46
The way QTimer is handled is that it is put into a queue sorted by time when it should fire next (now+interval). When events are processed by the application, when the event queue is already empty the dispatcher checks the timer queue. If the time of next timeout is less or equal to the current time, the timer is fired and if it is not single shot, it is rescheduled in the queue again (now+interval). I would assume there is also some mechanism to prevent latency buildup.

andariel
4th September 2014, 09:06
Wysota,
thanks a lot for that detailed explanation of how the QTimer works, very instructive. So this confirms there can be at any single point of time only one timer event for a given timer waiting to be executed.