简体   繁体   English

从不同的std :: thread更新Qt GUI

[英]Updating Qt GUI from a different std::thread

In a separate component of my application that I want to keep free of Qt dependency I am using std::thread for some operations. 在我想保持不受Qt依赖的应用程序的一个单独组件中,我使用std::thread进行某些操作。 I want to make changes in my main application during the processing. 我想在处理期间在主应用程序中进行更改。 For that I have attempted to pass a function (ie: function<void(UpdateNode*)> nodeUpdatedCallback ) to my component from my application. 为此,我尝试从我的应用程序向我的组件传递一个函数(即function<void(UpdateNode*)> nodeUpdatedCallback )。

This function updates the UI, but since I am calling that function from another thread, Qt says that I cannot access the UI from a non main thread. 此函数更新UI,但是由于我是从另一个线程调用该函数,因此Qt说我无法从非主线程访问UI。

I have seen many articles to solve this issue by using QThread and signals, creating a worker and moving it to that thread. 我看过许多文章通过使用QThread和信号来解决此问题,创建了一个worker并将其移至该线程。

Since I want to use std::thread , is it possible to update a UI based on Qt using std::thread ? 由于我想使用std::thread ,是否可以使用std::thread基于Qt更新UI?

When I used Qt in a multithreaded environment, and didn't want to/couldn't use idiomatic signals/slots, I added the following method to my objects: 当我在多线程环境中使用Qt且不想/不能使用惯用信号/插槽时,我向对象添加了以下方法:

    typedef std::function<void()> function_t;
    void executeInObjectsThread(function_t const&);

private slots:
    void executeInObjectsThreadSlot(function_t);

and the definition: 和定义:

void MyObj::executeInObjectsThread(function_t const& f)
{
    QMetaObject::invokeMethod(
        this,
        "executeInObjectsThreadSlot",
        Qt::QueuedConnection,
        Q_ARG(function_t,f)
    );
}

then in your other thread you'd just call 然后在另一个线程中,您只需调用

foo->executeInObjectsThread([=]{
    foo->addWidget(new QWidget(foo));
    // ...
    foo->editBox->setText(QString::number(currentResult));
    foo->progressBar->setValue(n);
});

Basically you're not, ever, supposed to modify any GUI related things from another thread. 基本上,您永远都不应该从另一个线程修改任何与GUI相关的内容。 There's a very good reason for this: GUIs depend on event loops that are not thread-safe. 这样做有一个很好的理由:GUI依赖于不是线程安全的事件循环。 You start playing with that, and you'll get undefined behavior due to race conditions. 您开始玩这个游戏,由于比赛条件,您将获得不确定的行为。 Thanks to Qt for protecting you from messing it up! 感谢Qt保护您避免混乱!

However, the solution to your problem is very simple. 但是,解决问题的方法非常简单。 What I do in your case is that I define a common variable that the thread-modifies. 在您的情况下,我要做的是定义一个线程修改的公共变量。 So I use a QTimer to check whether the thread has finished its job. 因此,我使用QTimer来检查线程是否已完成其工作。 And to know whether a thread has finished, you can use an std::atomic<bool> flag that will be set when the computation is over (or use std::promise/future , which I prefer). 要知道线程是否已经完成,可以使用将在计算结束时设置的std::atomic<bool>标志(或使用我更喜欢的std::promise/future )。 Then, the GUI will just read the (also thread-safe) results from the main thread and display them. 然后,GUI将只从主线程读取(也是线程安全的)结果并显示它们。 This is 100% safe. 这是100%安全的。

Recently I did this with Neblio. 最近,我与Neblio一起完成了此操作。 Check out my code there for an auto-updater that runs in another thread and displays the results on the GUI. 在这里检查我的代码,了解在另一个线程中运行并在GUI上显示结果的自动更新程序。

Qt indeed uses a signal/slot mechanism. Qt确实使用信号/时隙机制。 You only mention the signal part, but here the slot is very important too. 您仅提及信号部分,但此处的插槽也非常重要。 A slot lives in an object, and if that object is a Qt object with thread affinity then the slot will execute in that thread. 插槽位于对象中,如果该对象是具有线程相似性的Qt对象,则该插槽将在该线程中执行。 This holds even if the signal comes from another thread. 即使信号来自另一个线程,也是如此。

This is particularly useful when the slot owner is a QWindow or something similar with UI thread affinity. 当插槽所有者是QWindow或具有UI线程相似性的东西时,这特别有用。 It makes sure the UI code runs in the right thread. 确保UI代码在正确的线程中运行。 And almost certainly, the UI thread is the main() thread of your application. 几乎可以肯定,UI线程是应用程序的main()线程。

So you can still have a signal from your std::thread . 因此,您仍然可以从std::thread获得信号。 It won't cause the slot to run in the same std::thread . 它不会导致插槽在同一std::thread

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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