简体   繁体   中英

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 from 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 thread in spite of me calling for it from a worker thread ? If my approach is fine, then does it 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 ?

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 are. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM