【发布时间】:2018-05-14 11:35:54
【问题描述】:
我最近在用 c++ 开发基于 Qt 的应用程序时遇到了线程/内存问题,我正在寻找正确的解释。我不能真正发布一个功能齐全的示例,因为这需要链接到 Qt 等。但是用几行简短的代码可以很清楚地解释这个问题。
当我单击 gui 上的按钮时,会发生以下情况:
void MainWindow::onClick(){
std::vector<int> vec;
vec.push_back(0);
dev.connect(vec);
// do some more stuff
}
在这种情况下,dev 是MainWindow 的成员,并且属于Device 类类型,它代表我要连接的硬件(或更准确地说,硬件驱动程序)。 connect 的代码类似于:
void Device::connect(const std::vector<int>& vec){
// do some stuff with vec that takes a long time
}
我遇到的问题是设备驱动程序向我抛出异常,因为它们从 vec 中获取了错误的值。事实上,当我闯入connect 时,数据消失了:在那个范围内vec 是空内存。我使用shared_ptrs 解决了这个问题。
我的理论是,当我从 GUI 线程调用 dev.connect(vec) 时,Qt 实际上将该调用放在单独的线程上。然后,该函数需要很长时间,Qt 决定是时候继续并完成onClick(或类似的事情,也许它会立即发生)所以当vec 被Device::connect 处理时,它已经超出范围了。这符合 shared_ptr 在这里节省一天的事实。
所以我的问题是,我对此是否正确?有人可以解释Qt隐式线程行为的细节还是指出一些这样的解释?
【问题讨论】:
-
我相信它确实会产生(Qt 专用)线程。您可以使用调试器(Linux 上
pthread_create上的断点)找出答案。 This 是 GTK 的类似问题 -
Qt 做了一些隐式线程,但在这种情况下它不应该影响您 - MainWindow 的对象实例的 onClick 信号和您的插槽位于同一个对象上,因此发送/接收 qt 信号将在同一个对象上完成线程(除非您专门通过 Qt::Blocking/QueuedConnection)。您的设备类是从 QObject 派生的吗?如果是这样,请检查您没有隐式调用超类的 QObject 的 connect() 函数。您的 vec 何时超出范围?我假设您最后一个 vec.push() 和 dev.connect(vec) 之间的汇编代码足够短,可以提供答案。
-
绝对不,Qt 永远不会代表您做出这样的决定,文档warns many times 关于在 GUI 线程中做繁重的工作。相反,他们鼓励您(使用 Qt 的开发人员)offload heavy job to worker threads。像这样的事情永远不会隐式地完成,因为它总是会产生非常糟糕的副作用(正如你在问题中提到的那样)......
标签: c++ multithreading qt scope