默认情况下,从工作线程发出 Qt::signal 会使主线程上的 UI 更新?
Emitting a Qt::signal from worker thread makes the UI update on main thread by default?
我是 Qt
的新手。我有一个 std::thread
的工作线程。工作线程函数在循环中不断获取一些数据。 QML
UI 上的 Text
元素经常更新数据大小。我有一个侦听器回调,它只是一个 std::function
,它是从 thread's function
调用的。它根据我在 QML
上更新 Text
元素向我发送回调。我使用 signal slot
机制更新它。
以下是 QML : Text
元素:
Text {
id: mytext
objectName: "mytextobject"
function slotUpdateData(someValue){
mytext = someValue
}
}
SignalUpdateData
与位于 QML
侧的 slotUpdateData
相连。每次我从 std::thread
获得数据事件回调时,我 emit SignalUpdateData
都会更新 UI
上的 QML Text element
。
void CallBackReceivedFromWorkerThread(float someValue) {
emit SignalUpdateData(someValue)
}
以下是我如何将此 C++ signal
与 QML slot
联系起来
QObject::connect(this, SIGNAL(SignalUpdateData(QVariant)), myTextItemQObject, SLOT(slotUpdateData(QVariant)));
所有这一切都很好。没有崩溃、锁定,什么都没有。
根据我的理解,由于worker thread的函数触发了回调,所以当收到回调时,执行控制权在worker thread。所以当执行 emit SignalUpdateData(someValue)
时,我们仍然在工作线程上。 据我之前在 android
和 java
中的经验所知,我们无法从应用程序 main thread
之外的任何地方更新 UI。
那么,这是如何运作的? emit SignalUpdateData(someValue)
是否将呼叫放入 main UI thread's event loop
? Qt
是否仍在 main thread
上进行 UI 更改,尽管我从 worker thread
中调用它?如果我的方法没问题,那么它对性能有影响吗?这样做的最佳建议是什么?
我想对此非常确定,而不仅仅是幸运地让它发挥作用。我是否也应该使用 Qt::Connection_enum 以获得最佳方法?
您正在按照预期的方式利用 Qt!而且您不小心 运行 进入了它:这是一个体面设计的标志 - 它 "just works"。你万岁,Qt 万岁:)
之所以有效,是因为 Qt 专门设计用于使其有效,并且您正在使用默认的自动连接,其存在的理由是在这种特定情况下帮助您解决问题。所以你恰好做对了一切:什么都不改变!
当您发出信号时,Qt 获取相关的源和目标对象互斥量,并将接收对象的 thread()
与 QThread::currentThread()
进行比较。如果它们相同,则立即调用 slot/functor:它发生在信号主体中,因此在信号 returns 之前调用槽。这是安全的,因为目标对象是从其 thread()
安全的地方使用的。
如果target->thread() != QThread::currentThread()
,则QMetaCallEvent
排队到目标对象。该事件包含(等效的)插槽方法指针和插槽传递的任何参数的副本。 QObject::event
实现处理事件并执行调用。目标对象线程的事件循环在调用堆栈上,因为它的工作是将排队的事件传递给对象。
以上就是一个Qt::AutoConnection
的概括意思。如果您使用 Qt::QueuedConnection
,则无论线程是什么,第二种情况都适用。如果您使用 Qt::DirectConnection
,第一种情况无论如何都适用。
我的猜测是,在 SO 上的 Qt 相关问题中,>95% 的非自动连接类型的使用是不必要的,并且源于缺乏理解和求助于魔法咒语。
我是 Qt
的新手。我有一个 std::thread
的工作线程。工作线程函数在循环中不断获取一些数据。 QML
UI 上的 Text
元素经常更新数据大小。我有一个侦听器回调,它只是一个 std::function
,它是从 thread's function
调用的。它根据我在 QML
上更新 Text
元素向我发送回调。我使用 signal slot
机制更新它。
以下是 QML : Text
元素:
Text {
id: mytext
objectName: "mytextobject"
function slotUpdateData(someValue){
mytext = someValue
}
}
SignalUpdateData
与位于 QML
侧的 slotUpdateData
相连。每次我从 std::thread
获得数据事件回调时,我 emit SignalUpdateData
都会更新 UI
上的 QML Text element
。
void CallBackReceivedFromWorkerThread(float someValue) {
emit SignalUpdateData(someValue)
}
以下是我如何将此 C++ signal
与 QML slot
QObject::connect(this, SIGNAL(SignalUpdateData(QVariant)), myTextItemQObject, SLOT(slotUpdateData(QVariant)));
所有这一切都很好。没有崩溃、锁定,什么都没有。
根据我的理解,由于worker thread的函数触发了回调,所以当收到回调时,执行控制权在worker thread。所以当执行 emit SignalUpdateData(someValue)
时,我们仍然在工作线程上。 据我之前在 android
和 java
中的经验所知,我们无法从应用程序 main thread
之外的任何地方更新 UI。
那么,这是如何运作的? emit SignalUpdateData(someValue)
是否将呼叫放入 main UI thread's event loop
? Qt
是否仍在 main thread
上进行 UI 更改,尽管我从 worker thread
中调用它?如果我的方法没问题,那么它对性能有影响吗?这样做的最佳建议是什么?
我想对此非常确定,而不仅仅是幸运地让它发挥作用。我是否也应该使用 Qt::Connection_enum 以获得最佳方法?
您正在按照预期的方式利用 Qt!而且您不小心 运行 进入了它:这是一个体面设计的标志 - 它 "just works"。你万岁,Qt 万岁:)
之所以有效,是因为 Qt 专门设计用于使其有效,并且您正在使用默认的自动连接,其存在的理由是在这种特定情况下帮助您解决问题。所以你恰好做对了一切:什么都不改变!
当您发出信号时,Qt 获取相关的源和目标对象互斥量,并将接收对象的 thread()
与 QThread::currentThread()
进行比较。如果它们相同,则立即调用 slot/functor:它发生在信号主体中,因此在信号 returns 之前调用槽。这是安全的,因为目标对象是从其 thread()
安全的地方使用的。
如果target->thread() != QThread::currentThread()
,则QMetaCallEvent
排队到目标对象。该事件包含(等效的)插槽方法指针和插槽传递的任何参数的副本。 QObject::event
实现处理事件并执行调用。目标对象线程的事件循环在调用堆栈上,因为它的工作是将排队的事件传递给对象。
以上就是一个Qt::AutoConnection
的概括意思。如果您使用 Qt::QueuedConnection
,则无论线程是什么,第二种情况都适用。如果您使用 Qt::DirectConnection
,第一种情况无论如何都适用。
我的猜测是,在 SO 上的 Qt 相关问题中,>95% 的非自动连接类型的使用是不必要的,并且源于缺乏理解和求助于魔法咒语。