默认情况下,从工作线程发出 Qt::signal 会使主线程上的 UI 更新? [英] Emitting a Qt::signal from worker thread makes the UI update on main thread by default?

查看:37
本文介绍了默认情况下,从工作线程发出 Qt::signal 会使主线程上的 UI 更新?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 Qt 的新手.我有一个 std::thread 的工作线程.工作线程函数在一个循环中不断地获取一些数据.QML UI 上的 Text 元素经常更新数据的大小.我有一个监听器回调,它只不过是一个 std::function,它是从 thread 的函数 调用的.它根据我更新 QML 上的 Text 元素向我发送回调.我使用 signal slot 机制更新它.

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.

以下是 QML : Text 元素:

Text {
  id: mytext
  objectName: "mytextobject"

  function slotUpdateData(someValue){
    mytext = someValue
  }
}

SignalUpdateData 与位于 QML 端的 slotUpdateData 相连.每次我从 std::thread 获得数据事件回调时,我都会 发出 SignalUpdateData,它会更新 UI 上的 QML 文本元素.

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)
}

以下是我如何将此 C++ 信号QML 插槽

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

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

所有这些都可以正常工作.没有崩溃、锁定,什么都没有.

根据我的理解,由于工作线程的函数是触发回调的,所以在收到回调时执行控制在工作线程上.所以在执行 emit SignalUpdateData(someValue) 时,我们仍然在工作线程上.据我之前在 android &java,我们无法从应用程序的主线程之外的任何地方更新 UI.

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.

那么,这是如何工作的?emit SignalUpdateData(someValue) 是否将调用放入 主 UI 线程的事件循环 ?Qt 是否仍在 main thread 上进行 UI 更改,尽管我从 worker thread 调用它?如果我的方法很好,那么它是否会对性能产生影响?这样做的最佳建议是什么?

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 ?

我想对此非常确定&不仅仅是幸运地让它发挥作用.我是否应该最好使用 Qt::Connection_enum接近?

推荐答案

您正在以应有的方式利用 Qt!而你不小心碰到了它:这是一个体面设计的标志——它正常工作".你万岁,Qt 万岁 :)

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 :)

之所以有效,是因为 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!

当您发出信号时,Qt 会获取相关的源和目标对象互斥体,并将接收对象的 thread()QThread::currentThread() 进行比较.如果它们相同,则立即调用槽/函子:它发生在信号体中,因此在信号返回之前调用槽.这是安全的,因为目标对象是从它的 thread() 使用的,它是安全的.

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.

如果 target->thread() != QThread::currentThread(),则 QMetaCallEvent 将排队到目标对象.该事件包含(等效的)槽方法指针和槽传递的任何参数的副本.QObject::event 实现处理事件并执行调用.目标对象线程的事件循环位于调用堆栈上,因为它的工作是将排队的事件传递给对象.

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.

以上就是Qt::AutoConnection的意思.如果您使用的是 Qt::QueuedConnection,则无论线程是什么,第二种情况都适用.如果您使用的是 Qt::DirectConnection,则无论如何都适用第一种情况.

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.

我的猜测是,在关于 SO 的 Qt 相关问题中,>95% 的非自动连接类型的使用是不必要的,并且源于缺乏理解和诉诸魔法咒语.

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.

这篇关于默认情况下,从工作线程发出 Qt::signal 会使主线程上的 UI 更新?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆