PDA

View Full Version : Thread related questions



Cruz
21st February 2011, 16:21
Hi There!

I just wanted to ask about some details that are not clear to me after reading the documentation.

I intend to exchange data between threads using signals and slots. In the receiving thread, do I have to call exec() for the slots to fire? And when is the best time to do so? In the constructor? At the begining of run()? Or with each iteration of my infinite loop in the run() method?

When using queued connection and there are multiple signals waiting n the queue for the same slot, are they all guaranteed to be executed or only the last one in the queue?

Thanks
Cruz

high_flyer
21st February 2011, 16:35
do I have to call exec()
Not for the signals and slots.
exec() is for running a local thread event loop.


And when is the best time to do so?
When the data is ready to be sent.
But in truth, there is no absolute answer to this question - it depends on the inner logic of your application.
If you supply more information what the thread is doing, and what data it wants to send and for what purpose, it will be easier to say.


When using queued connection and there are multiple signals waiting n the queue for the same slot, are they all guaranteed to be executed or only the last one in the queue?
All of them will be executed, if you do not do something in your code to prevent it.

Cruz
21st February 2011, 16:45
Oh and most importantly: using signals and slots is thread safe, right?

wysota
21st February 2011, 21:39
Not for the signals and slots.
exec() is for running a local thread event loop.
Well, the thing is slots are delivered across threads using events so you need an event loop running to receive a cross-thread signal. You don't need it for emitting signals though.

high_flyer
22nd February 2011, 09:12
Well, the thing is slots are delivered across threads using events so you need an event loop running to receive a cross-thread signal.
You need the application event loop, not a local thread one.
You will receive signals, in a thread without a local event loop running, and you can send signals from such a thread object as well.

tbscope
22nd February 2011, 09:41
I think you need two event loops to have correct synchronisation.

wysota
22nd February 2011, 09:43
You need the application event loop, not a local thread one.
No, you need a local event loop.

Check out this example:

#include <QtGui>

class Object : public QObject {
Q_OBJECT
public slots:
void someSlot() { qDebug() << Q_FUNC_INFO; }
};

#include "main.moc"

class Thread : public QThread {
public:
Thread() { timer.start(1000); }
void run() {
Object o;
connect(&timer, SIGNAL(timeout()), &o, SLOT(someSlot()));
forever {
; // do nothing
}
}
private:
QTimer timer;
};

int main(int argc, char **argv){
QApplication app(argc, argv);
#if 1
QTimer timer;
Object o;
QObject::connect(&timer, SIGNAL(timeout()), &o, SLOT(someSlot()));
QThread thread;
thread.start();
o.moveToThread(&thread);
timer.start(1000);
#else
Thread thread;
thread.start();
#endif
return app.exec();
}

By default there is a local event loop running, if you change "#if 1" to "#if 0" there will be no local event loop running. See the result in both cases.

high_flyer
22nd February 2011, 10:17
if you change "#if 1" to "#if 0" there will be no local event loop running.
how so?
Why don't you have an event loop in #else?

wysota
22nd February 2011, 10:27
Because in Thread::run() there is no call to QThread::exec().

high_flyer
22nd February 2011, 10:34
By default there is a local event loop running,

Because in Thread::run() there is no call to QThread::exec().
Ah, yes, of course (docs):

By default, run() starts the event loop by calling exec()
Hmm.. it just occurred to me, that I as good as never used slots in my QThreads, rather I use set functions - which is where my confusion came form.
So far I didn't use slots, since if I was setting something in my thread, I wanted it at that time, and not leaving it to the event loop to decide.

Cruz
22nd February 2011, 10:47
In Wysota's example all signal processing is taking place in the thread. In #if 1 The object is moved to the thread, in #else there is just the thread sending signals to itself. So in this case Wysota is right, you need the event loop.

What high_flyer said, however, is that if you send signals between the main thread and a worker thread, you don't need to start event processing in the worker thread, because the main thread handles it. Having tried it this way I can confirm that it works. My thread receives signals from main and signals from the thread to main are also received and I never called exec().

wysota
22nd February 2011, 10:57
in #else there is just the thread sending signals to itself.
No, that's not true. The timer lives in the main thread and the "Object" lives in the worker thread.


Having tried it this way I can confirm that it works. My thread receives signals from main and signals from the thread to main are also received and I never called exec().
It means you don't have cross-thread signals :) The "Thread" object from my example and all its members live in the main thread. You can easily verify what I say, just add the following call to your main() and to the slot you assume works in a different thread and then compare the two values:

qDebug() << QThread::currentThreadId();

You'll see that in your case they are the same and in my case they are different.

In my example we get:
$ ./ev
App thread: 140623696955232
void Object::someSlot()
Object thread: 140623509120768

Here is a complete test code:

#include <QtGui>

class Object : public QObject {
Q_OBJECT
public slots:
void someSlot() {
qDebug() << Q_FUNC_INFO;
qDebug() << "Object thread:" << QThread::currentThreadId();
}
};

#include "main.moc"

class Thread : public QThread {
public:
Thread() {
timer.start(1000);
qDebug() << "Thread thread:" << QThread::currentThreadId();
}
void run() {
Object o;
connect(&timer, SIGNAL(timeout()), &o, SLOT(someSlot()));
qDebug() << "This is thread:" << QThread::currentThreadId();
qDebug() << "Does timer live in me? " << (timer.thread()==this ? "Yes" : "No");
qDebug() << "Does Object live in me? " << (o.thread()==this ? "Yes" : "No");
forever {
; // do nothing
}
}
private:
QTimer timer;
};

int main(int argc, char **argv){
QApplication app(argc, argv);
qDebug() << "App thread:" << QThread::currentThreadId();
#if 1
QTimer timer;
Object o;
QObject::connect(&timer, SIGNAL(timeout()), &o, SLOT(someSlot()));
QThread thread;
thread.start();
o.moveToThread(&thread);
timer.start(1000);
#else
Thread thread;
thread.start();
#endif
return app.exec();
}

And output in the second case:
App thread: 140557882951520
Thread thread: 140557882951520
This is thread: 140557695117056
Does timer live in me? No
Does Object live in me? Yes