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

2021-12-09 00:00:00 multithreading qt c++

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

I'm new to Qt, but need to solve a difficult problem.

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

I've created a VERY simple GUI that I need to add to an existing C++ application. The problem is, I'm writing just one module that plugs into a larger architecture which restricts my access to the main thread.

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

My code must reside inside the four following functions: an Init() function, which runs in the main thread. and WorkerStart(), WorkerStep(), and WorkerStop() functions that run in a worker thread.

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

I coded my QApplication and GUI objects in the Init() function. But of course, calling app.exec() at the end of that function blocks the entire rest of the code. Not workable.

我所读到的一切都表明 Qt gui 对象只能在主线程中运行.

Everything I'm reading says that Qt gui objects can only run in the main thread.

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

So my question is, how can I set up my gui in the init() function (main thread) and allow it to run by only using the worker thread from then on?

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

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

and those solutions gave me some different behavior. In the right direction, but not stable or fully functional. But I dont understand why those are solutions at all if qt gui's can only run in main thread, and these solutions put them in other threads. So thats sending mixed messages on what can and can not run in other threads, and it becomes very confusing.

向现有 C++ 程序添加 gui 而不将其锁定在 exec() 函数中似乎是一种相当普遍的情况,所以我觉得我遗漏了一些明显的东西.有人可以帮助我解决这个问题吗?

It seems that adding a gui to an existing C++ program without locking it up in the exec() func should be a fairly common situation so I feel like I'm missing something obvious. Can someone help with how I can solve this?

非常感谢.菲尔

推荐答案

大多数时候,主线程"==GUI 线程",所以人们交替使用这些术语――即使是官方文档也是如此.我同意这很令人困惑,因为它们不必相同.^ 实际规则是这样的:

Most of the time, "main thread" == "GUI thread", so people use those terms interchangeably -- even the official documentation does that. I agree that it's confusing though, because they don't have to be the same.^ The actual rule is this:

GUI 类只能从实例化 QApplication/QGuiApplication

GUI classes must only be accessed from the thread which instantiates QApplication/QGuiApplication

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

With a plugin like yours, here is what you need to do:

  1. 创建一个新的std::thread(不是QThread)
  2. 在该线程中运行 init 函数.让它实例化你的 QApplication/QGuiApplication 并启动事件循环
  3. 确保所有 GUI 对象只能从该线程访问.
  1. Create a new std::thread (NOT a QThread)
  2. Run an init function in that thread. Let it instantiate your QApplication/QGuiApplication and start the event loop
  3. Ensure that all your GUI objects are accessed from that thread only.

瞧,您现在拥有一个不是主线程的 GUI 线程.

Voila, you now have a GUI thread that is not your main thread.

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

^Note: It is a different story on Mac OS X. Due to restrictions in the Cocoa framework, the main thread MUST be the GUI thread. The steps I outlined above will work on Windows/Linux but not on Mac. For Mac, you need to inject your code into the main thread -- see Kuba Ober's comments below.

相关文章