PDA

View Full Version : Counter-intuitive behavior of QThreads signals/slots



reddish
7th September 2008, 17:33
Hi all,

I recently bumped into some curious behavior while implementing a program that uses QThreads.

Consider a "MyThread" class (a subclass of QThread) that implements an "updateTimerFired()" slot method. MyThread's "run" method instantiates a QTimer, connect the timer's timeout() signal to MyThread's updateTimerFired() slot, starts the timer, then executes exec() -- starting MyThread's private exec() loop.

The updateTimerFired() slot gets repeatedly executed as it should, but here's the catch: in what thread do you think that it runs?

Much to my surprise, it is executed not in MyThread's thread, but in the thread that has instantiated MyThread (in my case, the main thread).

To verify for yourself, you can download http://wopr.jigsaw.nl/wtf.tar.gz.

I think this behavior is completely counter-intuitive. Upon examining the Qt documentation, I found only a single line that explains this behavior:

http://doc.trolltech.com/4.4/threads.html#signals-and-slots-across-threads

"With queued connections, the slot is invoked when control returns to the event loop of the thread to which the object belongs. The slot is executed in the thread where the receiver object lives."

So what this boils down to is this: if a QThread derivative has a slot, it will not get executed by its own event loop, in its own thread. Therefore, you should be very wary of using slots in a QThread derivative, or even slots in a member function of a QThread-derived class. If you want a slot to be execute in the thread itself, this will only work if you instantiate the object with the slot within the run() method.

My feeling (after spending a day of chasing this issue) is that the Qt documentation could (or rather should) be a lot more specific to this. In particular, I think this should be mentioned in the documentation of the QThread class.

Any thoughts?

jacek
7th September 2008, 19:28
Upon examining the Qt documentation, I found only a single line that explains this behavior:[...]
You will have to read that document once more. The paragraph that explains this behavior is:

Like other objects, QThread objects live in the thread where the object was created -- not in the thread that is created when QThread::run() is called. It is generally unsafe to provide slots in your QThread subclass, unless you protect the member variables with a mutex.
Instead of subclassing QThread, put a QObject subclass inside the thread and all connections will behave as you expect.

reddish
8th September 2008, 00:26
You will have to read that document once more.

Indeed I will, I missed that part completely. Thanks for pointing it out.

wysota
9th September 2008, 20:40
Be aware that you can push the QThread object to its own thread so that its slots will be executed in the context of the thread created by that object.