如何避免 Qt app.exec() 阻塞主线程

问题描述 投票:0回答:2

我是Qt新手,但需要解决一个难题。

我创建了一个非常简单的 GUI,我需要将其添加到现有的 C++ 应用程序中。问题是,我只编写了一个插入更大架构的模块,这限制了我对主线程的访问。

我的代码必须驻留在以下四个函数中: Init() 函数,在主线程中运行。 以及在工作线程中运行的 WorkerStart()、WorkerStep() 和 WorkerStop() 函数。

我在 Init() 函数中编写了 QApplication 和 GUI 对象。当然,在该函数末尾调用 app.exec() 会阻塞整个其余代码。不可行。

我读到的所有内容都说 Qt gui 对象只能在主线程中运行。

所以我的问题是,如何在 init() 函数(主线程)中设置我的 gui,并允许它从此仅使用工作线程来运行?

我发现了这个:非主线程中的QApplication

这些解决方案给了我一些不同的行为。方向正确,但不稳定或功能不齐全。但我不明白为什么这些是解决方案,如果 qt gui 只能在主线程中运行,并且这些解决方案将它们放在其他线程中。因此,这会发送关于什么可以在其他线程中运行、什么不能在其他线程中运行的混合消息,这会变得非常混乱。

似乎将 gui 添加到现有的 C++ 程序而不将其锁定在 exec() 函数中应该是相当常见的情况,所以我觉得我错过了一些明显的东西。有人可以帮我解决这个问题吗?

提前非常感谢。 菲尔

c++ multithreading qt
2个回答
29
投票

大多数时候,“主线程”==“GUI 线程”,因此人们可以互换使用这些术语——甚至官方文档也是如此。我同意这很令人困惑,因为它们不必相同。^ 实际规则是这样的:

GUI 类只能从实例化的线程访问

QApplication
/
QGuiApplication

使用像您这样的插件,您需要执行以下操作:

  1. 创建一个新的
    std::thread
    (不是
    QThread
  2. 在该线程中运行
    init
    函数。让它实例化您的
    QApplication
    /
    QGuiApplication
    并启动事件循环
  3. 确保所有 GUI 对象只能从该线程访问。

瞧,你现在有一个 GUI 线程,它不是你的主线程。


^注意:Mac OS X 上情况不同。由于 Cocoa 框架的限制,主线程必须是 GUI 线程。我上面概述的步骤适用于 Windows/Linux,但不适用于 Mac。对于 Mac,您需要将代码注入主线程 - 请参阅下面 Kuba Ober 的评论。


0
投票

在这里找到了一个很好的解决方案,可以像这样使用:

run_in_gui_thread(new RunEventImpl([](){ QMainWindow* window=new QMainWindow(); window->show(); }));
可以随时从任何线程调用,同时在后台为您进行设置。 

注意,这还负责创建一个 QApplication

 并在线程中执行它。但如果您已经在某处这样做过,也可以使用。

© www.soinside.com 2019 - 2024. All rights reserved.