从另一个std :: thread更新Qt GUI

时间:2018-03-27 10:06:28

标签: c++ multithreading qt

在我的应用程序的一个单独组件中,我希望保持Qt依赖性,我正在使用std::thread进行某些操作。我想在处理过程中对主应用程序进行更改。为此,我试图将一个函数(即:function<void(UpdateNode*)> nodeUpdatedCallback)从我的应用程序传递给我的组件。

这个函数更新了UI,但由于我从另一个线程调用该函数,Qt说我无法从非主线程访问UI。

我已经看过许多文章通过使用QThread和信号来解决这个问题,创建一个worker并将其移动到该线程。

由于我想使用std::thread,是否可以使用std::thread更新基于Qt的用户界面?

3 个答案:

答案 0 :(得分:2)

当我在多线程环境中使用Qt,并且不想/不能使用惯用信号/插槽时,我将以下方法添加到我的对象中:

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

private slots:
    void executeInObjectsThreadSlot(function_t);

和定义:

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

然后在你的另一个帖子中,你只需要打电话

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

答案 1 :(得分:1)

基本上你不应该从另一个线程修改任何GUI相关的东西。这有一个很好的理由:GUI依赖于非线程安全的事件循环。你开始玩它,你会因竞争条件而得到不确定的行为。感谢Qt保护你免受搞乱!

但是,您的问题的解决方案非常简单。我在你的情况下做的是我定义一个线程修改的公共变量。所以我使用QTimer来检查线程是否已完成其工作。要知道线程是否已完成,您可以使用将在计算结束时设置的std::atomic<bool>标志(或使用std::promise/future,我更喜欢)。然后,GUI将只读取主线程的(也是线程安全的)结果并显示它们。这是100%安全的。

最近我和Neblio这样做了。 Check out my code there表示在另一个线程中运行的自动更新程序,并在GUI上显示结果。

答案 2 :(得分:1)

Qt确实使用信号/插槽机制。你只提到信号部分,但这里的插槽也非常重要。一个槽位于一个对象中,如果该对象是一个具有线程关联性的Qt对象,则该槽将在该线程中执行。即使信号来自另一个线程,这也成立。

当插槽所有者为QWindow或类似于UI线程关联的东西时,这尤其有用。它确保UI代码在正确的线程中运行。几乎可以肯定,UI线程是应用程序的main()线程。

所以你仍然可以从std::thread获得信号。它不会导致插槽在同一std::thread中运行。