[Development] Why is QSignalSpy using Qt::DirectConnection?

Roland Winklmeier roland.m.winklmeier at gmail.com
Sun Oct 26 16:34:29 CET 2014

As promissed I had a look into QTestEventLoop.

> QSignalSpy::wait() isn't thread-safe because it's using QTestEventLoop instead 
> of a regular QEventLoop. That former does use a timer and, unlike the latter, 
> you can't stop the loop from outside the loop's own thread.

Just to be sure: The reason why you cannot stop a QTestEventLoop from
outside the loops own thread is because of the running timer?
QTestEventLoop owns a QEventLoop and extends it with the timer.

Anyhow, I found a potential fix and would like to hear your opinions
before submitting it.

Lets say QSignalSpy runs in thread 0, while another QObject runs in
thread 1. When running QSignalSpy::wait() two situations can happen:

1. QTestEventLoop's internal timer will time out and exit its own loop.
Since QSignalSpy and QTestEventLoop run in the same thread 0, it's all fine.

2. The connected signal is emitted and QSignalSpy will try to stop the
event loop internally in its slot. Due to the Qt::DirectConnection, this
will happen in the thread which emitted the signal, so thread 1 -> Error

The easiest fix would be to make QTestEventLoop::exitLoop() thread-safe
by adding the if condition at the beginning of the method:

if (thread() != QThread::currentThread())
    QMetaObject::invokeMethod(this, "exitLoop", Qt::QueuedConnection);

If it is called from a different thread, it will post an event into its
own event queue and call the slot again from the correct thread and
execute there.

Would this fix be acceptable?

More information about the Development mailing list