Segmentation Fault Segmentation Fault - 19 days ago 6
C++ Question

Emitting a Qt::signal from worker thread makes the UI update on main thread by default?

I am new to

Qt
. I have worker thread that is an
std::thread
. The worker thread function continuously fetches some some data in a loop. The size of the data is frequently updated on a
Text
element on a
QML
UI. I have a listener callback which is nothing but an
std::function
and it gets called from the
thread's function
. It sends me callbacks based on which I updated the
Text
element on
QML
. I update it using
signal slot
mechanism.

Following is the
QML : Text
element:

Text {
id: mytext
objectName: "mytextobject"

function slotUpdateData(someValue){
mytext = someValue
}
}


SignalUpdateData
is connected with
slotUpdateData
which resides on
QML
side. Every time I get the data event callback from the
std::thread
, I
emit SignalUpdateData
which updates the
QML Text element
on
UI
.

void CallBackReceivedFromWorkerThread(float someValue) {
emit SignalUpdateData(someValue)
}


Following is how I have connected this
C++ signal
with the
QML slot


QObject::connect(this, SIGNAL(SignalUpdateData(QVariant)), myTextItemQObject, SLOT(slotUpdateData(QVariant)));


And all of this works fine. No crashes, lock-ups, nothing.

As per my understanding, since the worker thread's function is triggering the callback, the execution control is on the worker thread when the callback is received. So when doing
emit SignalUpdateData(someValue)
, we'er still on the worker thread. And as far as I know my previous experience in
android
&
java
, we cannot update the UI from anywhere outside the
main thread
of the application.


So, How is this working ? Is
emit SignalUpdateData(someValue)
putting the call into the
main UI thread's event loop
? Is
Qt
still making the UI change on
main UI thread
even if I am calling it from
worker thread
? Does this have performance implications ? What is the best recommendation to do this ?


I want to be very sure about this & not just lucky about making this to work. Should I use a Qt::Connection_enum as well for best approach ?

Answer

You're leveraging Qt the way it was meant to be! And you've run into it accidentally: that's a sign of a decent design - it "just works". Hooray for you, hooray for Qt :)

It's working because Qt has been designed specifically to make it work, and you're using the default automatic connection whose raison d'ĂȘtre is to help you out in this specific case. So you happen to be doing everything right: change nothing!

When you emit a signal, Qt acquires relevant source and destination object mutexes, and compares the receiving object's thread() to QThread::currentThread(). If they are identical, the slot/functor is called immediately: it happens in the body of the signal, so the slot is called before the signal returns. This is safe as the target object is used from its thread(), where it's safe.

If target->thread() != QThread::currentThread(), then a QMetaCallEvent is queued to the target object. The event contains the (equivalent of) slot method pointer and a copy of any parameters passed by the slot. The QObject::event implementation handles the event and executes the call. The target object thread's event loop is on the call stack, since its job is to deliver the queued events to the object.

The above is, in a nutshell the meaning of a Qt::AutoConnection. If you're using Qt::QueuedConnection, the 2nd case applies no matter what the threads area If you're using Qt::DirectConnection, the 1st case applies no matter what.

My guess is that >95% of the uses of a non-automatic connection type in Qt-related questions on SO are unnecessary and stem from lack of understanding and resorting to what amounts to magic incantations.