默认情况下,从工作线程发出 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.
相关文章