当从外部对象调用方法时,QT的GUI线程是否会在后台创建线程?

4

最近我在开发一款基于Qt和C ++的应用程序时遇到了线程/内存问题,现在正在寻找正确的解释。我无法提供完全运行的示例,因为那需要链接到Qt等。但问题可以在几行简短的说明中清楚地解释。

当我在界面上点击一个按钮时,会出现如下情况:

void MainWindow::onClick(){

    std::vector<int> vec;
    vec.push_back(0);

    dev.connect(vec);

    // do some more stuff
}

在这个例子中,devMainWindow 的成员,是一个代表硬件(或更准确地说,硬件驱动程序)的类类型为 Device。我想要连接它们。connect 的代码大致如下:
void Device::connect(const std::vector<int>& vec){
    // do some stuff with vec that takes a long time
}

我遇到的问题是设备驱动程序抛出异常,因为它们从 `vec` 中获取了错误值。事实上,当我打断点进入 `connect` 时,数据已经消失了:在那个作用域中,`vec` 是空的内存。我通过使用 `shared_ptr` 来解决这个问题。
我的理论是,当我从 GUI 线程调用 `dev.connect(vec)` 时,Qt 实际上会将该调用放在一个单独的线程中。然后,该函数需要很长时间,Qt 决定是时候继续完成 `onClick` 了(或者类似的操作,也许立即发生),因此当 `vec` 在 `Device::connect` 中处理时,它已经超出了作用域。考虑到 `shared_ptr` 在这里拯救了一天,这与我的理论相符。
所以我的问题是,我的理论正确吗?有人能解释一下 Qt 的隐式线程行为的详细信息或指向这样的说明吗?

我相信它确实会生成(对Qt私有的)线程。你可以通过调试器找出来(在Linux上在pthread_create处设置断点)。这是一个类似的关于GTK的问题。 - Basile Starynkevitch
Qt在某些情况下会进行隐式线程处理,但这不应该影响到您的情况——MainWindow对象实例的onClick信号和您的槽函数位于同一对象上,因此发送/接收qt信号将在同一线程上完成(除非您明确传递了Qt::Blocking/QueuedConnection)。您的Device类是从QObject派生的吗?如果是的话,请检查是否在隐式调用超类的QObject的connect()函数。您的vec在哪个时刻超出了作用域?我假设在最后一个vec.push()和dev.connect(vec)之间的汇编代码足够短以提供答案。 - markus-nm
绝对不是这样的,Qt从不代表您做出这样的决定。文档多次警告不要在GUI线程中执行繁重的工作。相反,他们鼓励您(作为使用Qt的开发人员)将繁重的工作转移到工作线程中。像这样的事情永远不能隐式地完成,因为它总会产生非常严重的副作用(正如您在问题中提到的)。 - Mike
我不能真正发布一个完全功能的示例,因为那需要链接到Qt等等。嗯,你不必在你的回答中链接到Qt。大多数人都已经安装了Qt,他们可以尝试运行你的代码。对于尝试运行你的代码的人来说,所需的努力越小,就越好。我在这里的许多答案都是MCVEs(123,...)。你只需要将我的答案中的代码复制粘贴到一个main.cpp文件中,即可运行它... - Mike
2个回答

1
你所问的是,QT ui线程在某些任务中需要花费很长时间,以至于它被中断,从一个函数返回,然后尝试从离开的地方继续执行,这是否可能。
答案是否定的。如果线程被中断,那么它要么会回到原来的位置,要么即将终止。试图做其他事情可能会被病毒扫描程序标记并引入严重的错误。
如果您尝试在UI线程中执行耗时操作,则可能会导致UI无响应,并且操作系统会抱怨应用程序变得无响应(因为应用程序无法再响应操作系统发送给它的事件)。
更有可能的情况是,在QT中引发信号时,不能保证立即传递给插槽,因此您将陷入您所描述的情况。
shared_ptr“拯救了一天”的事实意味着您没有看到堆栈损坏的情况(这是件好事,因为它们很难调试)。一个简单的堆栈跟踪应该能回答您的问题。

0

加一分给UKMonkey,因为答案确实是“不”。谢谢你提供的详细信息。

进一步调查后,我发现实际上存在另一个问题,这个问题始终是设备驱动程序投诉的核心。我之前认为问题出在向量那里,因为(在这种特殊情况下)空向量可能会导致异常的根源,而且调试器显示为空。使用shared_ptr,我在向量中看到了值,但仍然会出现异常。然后,我找到了异常的(无关的真正)原因,并进行了修复。回到非shared_ptr版本(但已经解决了无关抛出异常的错误),代码按预期运行。

所以,这只是一个误导。但是,我很高兴知道答案确实是“不”。Qt在处理像这样的直接场景时,并不会有任何有趣的线程操作。我展示的代码确实会在调用connect时阻塞。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接