从工作线程发出Qt :: signal会默认在主线程上进行UI更新?

时间:2016-11-21 20:00:18

标签: c++ multithreading qt qml signals-slots

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

以下是QML : Text元素:

Text {
  id: mytext
  objectName: "mytextobject"

  function slotUpdateData(someValue){
    mytext = someValue
  }
}

SignalUpdateData与位于slotUpdateData方的QML相关联。每次我从std::thread获取数据事件回调时,我emit SignalUpdateData会更新QML Text element上的UI

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

以下是我将此C++ signalQML slot

相关联的方法
QObject::connect(this, SIGNAL(SignalUpdateData(QVariant)), myTextItemQObject, SLOT(slotUpdateData(QVariant)));

所有这一切都很好。没有崩溃,没有锁定,没有。

根据我的理解,由于工作线程的功能正在触发回调,因此当收到回调时,执行控制在工作线程上。所以当做emit SignalUpdateData(someValue)时,我们仍然在工作线程上。 据我之前在android& java,我们无法在应用程序main thread之外的任何位置更新用户界面。

所以,这是如何工作的? emit SignalUpdateData(someValue)将来电置于main UI thread's event loop吗?尽管Qt要求main threadworker thread仍在 @font-face { font-family: ProximaNova; src: url("../fonts/ProximaNova-Regular.otf") format("opentype"); font-weight: 400; } @font-face { font-family: ProximaNova; src: url("../fonts/ProximaNova-Semibold.otf") format("opentype"); font-weight: 500; } @font-face { font-family: ProximaNova; src: url("../fonts/ProximaNova-Bold.otf") format("opentype"); font-weight: bold; } @font-face { font-family: ProximaNova; src: url("../fonts/ProximaNova-Light.otf") format("opentype"); font-weight: 300; } @font-face { font-family: ProximaNova; src: url("../fonts/ProximaNova-Thin.otf") format("opentype"); font-weight: lighter; } 进行用户界面更改吗?如果我的方法很好,那么它是否具有性能影响?这样做的最佳建议是什么?

我想非常肯定这个&让这个工作起来并不幸运。我是否应该使用Qt::Connection_enum以获得最佳方法?

1 个答案:

答案 0 :(得分:7)

你正在利用Qt的方式!你不小心碰到了它:这是一个体面设计的标志 - 它“只是有效”。万岁适合你,对Qt万岁:)

这是有效的,因为Qt专门设计用于使其工作,并且您正在使用默认的自动连接,其存在的理由是帮助您解决这一特定情况。所以你碰巧正在做正确的事:不做任何改变!

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

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

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

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