[Solved] Qt::DirectConnection querries for multi threaded application?
I have some querries regarding how SIGNAL SLOT behave in multi threaded use case.
Consider the following connection:
@connect(parentObj, SIGNAL(sig1()), workerObj, SLOT(slot1()), Qt::DirectConnection);
//workerObj is moved to different QThread.@
- Is it guaranteed that qDebug() will be executed only after slot1() is executed?
- In which thread is slot1 executed, parentObj thread or workerObj thread?
- Instead of above code if I use
i.e. through parentObj thread is it correct/legal?
- Declaration of a SIGNAL requires a return type. So if the connection is Direct, is it guaranteed that the return value from the emit statement will be the same value as returned by the connected SLOT?
connect(parentObj, SIGNAL(sig2(bool)), workerObj, SLOT(slot2(bool)), Qt::DirectConnection);
bool result = emit sig2();//is this legal?@
First, I recommend reading these 2 sections:
- "QObject: Thread Affinity":http://qt-project.org/doc/qt-5/qobject.html#thread-affinity
Second, remember that a QObject is not thread-safe. You are only allowed to access the object from one thread; you are not allowed to call its functions from a different thread.
Third, to answer your questions:
- Technically, yes. But, you should NOT force Qt::DirectConnection when the object lives in a different thread.
- Qt::DirectConnection will cause the slot to be called in the thread that emits the signal.
- No. Direct vs. Queued only affects when and in which thread the slot is invoked. Direct connection does not link the slot's return value to the signal's return value.
To add to JKSH, signals return value is void as explained "here":http://qt-project.org/doc/qt-5/signalsandslots.html#signals
If you want to invoke a method on an object which returns something you should use Q_INVOKABLE and related methods
Thank you for providing the links.
bq. The slot is invoked immediately, when the signal is emitted.
The documentation does not mention in which thread the slot will be executed. Perhaps it can be added for next build?
I did not know that Qt::DirectConnection causes the slot to be executed in the emitting thread. Thanks for telling me that. This pretty much answers my 3 questions.
Now in my use case I need to get a value from an object moved to a different thread. The value must be returned immediately similar to like a function return value. This is because this return value is required in the next line of code. How do I achieve this?
Thanks for the information about signals. From the code in question:
@bool result = emit sig2();@
I need to get a return value from an object moved to a different thread.
I am using result in next line, so the next line must be executed only after the slot is executed and return value obtained. Now how do I do this?
My previous attempts with Qt::DirectConnection seems futile.
Then have a look at the invokeMethod documentation and the Qt::BlockingQueuedConnection
You're welcome :)
The method SGaist mentioned is QMetaObject::invokeMethod().
[quote]The documentation does not mention in which thread the slot will be executed. Perhaps it can be added for next build?[/quote]Done: https://codereview.qt-project.org/#patch,all,74441,2
The Qt Project is run under Open Governance. If you see something that can be fixed/improved quickly, feel free to send a patch yourself! (See http://qt-project.org/wiki/Gerrit-Introduction for info) If you can't make your own patch, submit ideas/bug reports to http://bugreports.qt-project.org/ (reports in this forum will get buried)
@SGaist, Qt::BlockingQueuedConnection was exactly I was looking for. Silly of me for not looking at all the connection types.
@JKSH now that I understand BlockingQueuedConnection I am unable to understand why anybody would be requiring to use invokeMethod()? SIGNAL and SLOT is so much more clean and easy to use.
OK got it about the bug reporting. I will send the patch next time. :)
You can emit a signal too if you prefer. invokeMethod() is for cases where:
- You want to invoke a slot without creating a signal, and/or
- You want to retrieve the slot's return value.
I'm not sure that the signal/slot technique is always cleaner though :)
// Signal/slot technique
connect(this, SIGNAL(sig2()), workerObj, SLOT(slot2()), Qt::BlockingQueuedConnection);
// invokeMethod() technique
QMetaObject::invokeMethod(workerObj, "slot2", Qt::BlockingQueuedConnection);
A third case for invokeMethod is calling a Q_INVOKABLE method which is not the same thing as a slot.
And I agree with JKSH, in this case I would rather go with invokeMethod which is cleaner logic and code wise.