[Qt-interest] Do QTimer Race Conditions Exist

Will Rutherdale (rutherw) rutherw at cisco.com
Thu Feb 11 21:09:38 CET 2010


> -----Original Message-----
> From: qt-interest-bounces at trolltech.com 
> [mailto:qt-interest-bounces at trolltech.com] On Behalf Of 
> Andreas Pakulat
> Sent: 11 February 2010 13:51
> To: qt-interest at trolltech.com
> Subject: Re: [Qt-interest] Do QTimer Race Conditions Exist
> 
> On 11.02.10 10:07:23, Will Rutherdale (rutherw) wrote:
> > I am wondering about reliability of QTimer if it is used in certain
> > ways.  I am not questioning the internal robustness, but 
> whether I have
> > to take certain precautions in using it.  I have an 
> application where
> > getting it right is critical.  On the other hand I don't want to
> > over-engineer if it is not necessary.
> > 
> > The situation is like this.  Suppose I have a class criticalClass
> > derived from QObject with these slots:
> > 
> >     void slotFoo();
> >     void slotTimerResponse();
> > 
> > Also my class has a timer, used in singleshot mode:
> > 
> >     QTimer *timer_t_;
> > 
> > Also, a connect() has been done between timer_t_'s 
> timeout() signal and
> > slotTimerResponse().  And suppose somewhere in the code I do this:
> > 
> >     timer_t_->start();
> > 
> > Now slotTimerResponse():
> > 
> > void criticalClass::slotTimerResponse()
> > {
> >     qCritical() << "Holy smokes what a HORRIBLE thing:  the 
> timer has
> > expired.  Blowing up the whole system in despair!!!";
> >     // ...
> > }
> > 
> > Now somewhere else in the code, in slotFoo(), while the 
> timer is active,
> > some expected event happens and the code does this:
> > 
> >     timer_t_->stop();
> > 
> > My question:  is it enough that I called stop() on the timer inside
> > slotFoo()?  I can see that the timer will stop running at 
> that point,
> > but is it not also possible that, in parallel with that, 
> while that slot
> > is active, the timer will emit its signal timeout().
> 
> Not unless you run a multi-threaded application with slotFoo executing
> in one thread and the eventloop which "executes" the timer in another.
> The reason is simply that while a slot is executed the event loop
> doesn't run and hence the timer doesn't get its 
> timeout-event. QTimer is
> event-based, hence it can only emit its signal once it receives its
> QTimerEvent(). That doesn't happen if the event-loop is run. As
> non-timer slot execution usually happens due to some kind of event
> (user-input etc.) the slot blocks the event loop.
> 
> If you want to know for sure: qtimer.cpp in the Qt sources isn't that
> complicated and IIRC neither is the function calls it does to actually
> create/start a timer.
> 
> Andreas

Thanks for the response.

I am only using the timer in the same thread (and event loop) as the
application code, so there is not likely an issue there.

Nevertheless my concern was, since the timer event comes from an
external source that is ultimately hardware (or unix signal) driven,
that it still might put something into the event loop.

I took your advice and looked at qtimer.cpp.  The relevant code snippets
I found were:

- QTimer::stop() sets id to INV_TIMER
- QTimer::timerEvent() tests against this id before doing the 'emit
timeout()'

So this mostly looks like I have nothing to fear.  But then considering
further, the situation that can arise is that soon after my
timer_t_->stop() call, I might issue another timer_t_->start() call.
The danger is potentially re-opened.

Looking again at the source, QTimer::start() re-assigns a new value to
the id like this:

id = QObject::startTimer(inter);

Then QObject::startTimer() has some slightly obfuscated code with a
Q_D() macro and a mysterious variable called 'd' through which an
eventDispatcher has its registerTimer() called, and that ultimately
produces the new id.  Presumably this eventDispatcher and
registerTimer() code map to some Linux-specific code that returns
different ids.

If I take it on faith that this new id is different from the previous
few, then yes I am okay, because any pending timer event will contain a
timer id that is not equal to the current timer id.  If however the id
could come back with the same value on successive calls, then I could be
in trouble.

Any idea whether these id's are unique and where I can verify that?

-Will




More information about the Qt-interest-old mailing list