PDA

View Full Version : Moving QObject to QThread causes signals to stop working



Ban-chan
13th July 2010, 17:00
I know that QThreads are a tricky issue for most. I've read through a lot of examples and documentation to setup my threading correctly under QT. The 2 methods seem to be sub-classing QThread (which although the documentation says to do this, it is apparently the incorrect way) and the other is subclassing QObject and then moving it to a thread. Trying both methods I was unable to get a simple signal in the thread to connect to a slot in my main thread.

For the first method if I did not use moveToThread(this) in the subclassed QThread constructor, it would not execute in a new thread, but the signals worked. Using moveToThread(this) caused the connection to be broken in some way.

Trying it the 2nd method, my signals in the worker object worked until I moved them to a QThread.

Are there any known issues with using QThread under QT 4.6.3 and compiling with MSVC 2010 on Win7 x64( the app is compiled as 32-bit)?

The signal I'm emitting is a QString (declare as: void StringSignal(QString&);, used as: emit StringSignal(QString("Hello"));)
In the first method the connection is made as:

connect(&thread,SIGNAL(StringSignal(QString&)),this,SLOT(SignalSlot(QString&)));)

My code isn't any different than the Mandelbrot example (for the first method I tried). I call a function in the QThread that sets some values and either starts the thread if it isn't running or wakes the QWaitCondition.

wysota
13th July 2010, 18:56
Does the thread run an event loop?

Ban-chan
13th July 2010, 19:02
As in do I call exec() in the run function? I do not. But they don't in the Mandelbrot example either and it works just fine.

tbscope
13th July 2010, 19:18
The mandelbrot example isn't a good one, in fact it isn't even correct although it works.

QThread changed around Qt4.2 or 4.3 to start an event loop when starting a thread. The problem is that when you subclass QThread and implement the run() function, the automatic event loop is lost and you need to start it yourself.

That's why it is recommended not to subclass QThread at all and use either Qt Concurrent classes or create a QObject and move it to a thread.

Can you post the code where you created a QObject subclass and moved it to a thread?

wysota
13th July 2010, 20:19
As in do I call exec() in the run function? I do not.
Then you don't get to be notified about signals from other threads.


But they don't in the Mandelbrot example either and it works just fine.
Oh, I'm sure the thread where slots are executed (which happens to be the main thread in this case) has an event loop running.

Ban-chan
13th July 2010, 22:00
Then you don't get to be notified about signals from other threads.

That's fine I'm just emiting Signals from the thread. I don't have any slots in it.



Oh, I'm sure the thread where slots are executed (which happens to be the main thread in this case) has an event loop running.
Yes, as does my main thread (GUI thread).

Ban-chan
13th July 2010, 22:15
The mandelbrot example isn't a good one, in fact it isn't even correct although it works.

QThread changed around Qt4.2 or 4.3 to start an event loop when starting a thread. The problem is that when you subclass QThread and implement the run() function, the automatic event loop is lost and you need to start it yourself.

That's why it is recommended not to subclass QThread at all and use either Qt Concurrent classes or create a QObject and move it to a thread.

Can you post the code where you created a QObject subclass and moved it to a thread?

I have a few questions to make sure I'm doing this method right in the first place.
Is the proper method of doing this to setup"tasks" in the QObject as slots that I call from my main thread (GUI thread)? The exec() default implementation would ensure I have an event loop in the QThread I move it too, correct? Or should I link the started() signal from the QThread to a slot in my QObject that uses a forever loop and QWaitConditions, similar to what is shown in the Mandelbrot example?

tbscope
13th July 2010, 22:22
I have a few questions to make sure I'm doing this method right in the first place.
Is the proper method of doing this to setup"tasks" in the QObject as slots that I call from my main thread (GUI thread)?

I'm not sure what you mean exactly. But I guess yes, you create a QObject based class just like any other. As an example, you can consider a class for calculating prime numbers in a certain range. You can create a function or even a slot to set the range (and link this slot to a slider for example). And create a slot to start calculating etc...


The exec() default implementation would ensure I have an event loop in the QThread I move it too, correct?
Yes, QThread by default takes care of the event loop.


Or should I link the started() signal from the QThread to a slot in my QObject that uses a forever loop and QWaitConditions, similar to what is shown in the Mandelbrot example?
No, you shouldn't need to do that since the event loop (started with exec() ) runs till you call quit().

Here's an example:
http://labs.trolltech.com/blogs/2006/12/04/threading-without-the-headache/

wysota
13th July 2010, 22:39
I would like to protest against a blind argument that subclassing QThread doesn't make sense anymore. Let's consider the prime number situation. It's much easier to do this:

class PrimeThread : public QThread {
Q_OBJECT
public:
void run() { for(int i=1;i<1000;i++) if(isPrime(i)) emit prime(i); }
signals:
void prime(int);
//...
};

PrimeThread thread;
thread.start();
than this:


class PrimeObject : public QObject {
Q_OBJECT
public slots:
void run() {
for(int i=1;i<1000;i++) if(isPrime(i)) emit prime(i);
emit quit();
}
signals:
void prime(int);
void quit();
};

QThread thread;
thread.start();
PrimeObject o;
connect(&o, SIGNAL(quit()), &thread, SLOT(quit()));
o.moveToThread(&thread);
QMetaObject::invokeMethod(&o, "run", Qt::QueuedConnection);