- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有
struct MyWidget : QWidget {
// non-GUI related stuff:
int data;
int doSth();
};
我需要从另一个线程(即不是主线程)访问一个 MyWidget
实例。有什么办法可以安全地做到这一点?我知道我无法访问 GUI 相关功能,因为某些后端(例如 MacOSX/Cocoa)不支持。但是,在此示例中,我只需要访问 data
或 doSth()
。但据我所知,根本没有办法保证对象的生命周期 - 即如果带有该小部件的父窗口关闭,MyWidget
实例将被删除。
或者有没有办法保证生命周期?我猜想 QSharedPointer
不起作用,因为 QWidget
在内部执行其生命周期处理,具体取决于父窗口小部件。 QPointer
当然也无济于事,因为它很弱而且没有锁定机制。
我目前的解决方法基本上是:
int widget_doSth(QPointer<MyWidget> w) {
int ret = -1;
execInMainThread_sync([&]() {
if(w)
ret = w->doSth();
});
return ret;
}
(execInMainThread_sync
通过使用 QMetaMethod::invoke
调用主线程中的方法来工作。)
但是,由于某些特定原因,该解决方法不再有效(稍后我将解释原因,但这并不重要)。基本上,那时我无法在主线程中执行某些操作(出于某些复杂的死锁原因)。
我目前正在考虑的另一个解决方法是添加一个全局互斥锁来保护 MyWidget
析构函数,并且在析构函数中,我正在清理对 MyWidget 的其他弱引用
。然后,在其他地方,当我需要确保生命周期时,我只需锁定那个互斥量。
我当前的解决方法不再起作用的原因(这仍然是实际情况的简化版本):
在MyWidget
中,data
实际上是一个PyObject*
。
在主线程中,一些 Python 代码被调用。 (在我的应用程序的主线程中完全避免任何 Python 代码调用是不可能的。)Python 代码最终会执行一些 import
,它由一些 Python-import-mutex(Python不允许并行导入
。)
在其他一些 Python 线程中,调用了其他一些 import
。 import
现在锁定了 Python-import-mutex。当它在做它的事情时,它会在某个时候进行一些 GC 清理。该 GC 清理调用某个对象的遍历函数,该对象包含该 MyWidget
。因此,它必须访问 MyWidget
。但是,execInMainThread_sync
(或等效的工作解决方案)将死锁,因为主线程当前正在等待 Python 导入锁。
注意:Python 全局解释器锁并不是真正的问题所在。当然,它会在任何 execInMainThread_sync
调用之前解锁。但是,我无法真正检查任何其他潜在的 Python/任何锁。特别是我不被允许只解锁 Python 导入锁——它在那里是有原因的。
您可能会想到的一个解决方案是完全避免在主线程中使用任何 Python 代码。但这有很多缺点,例如它会很慢、复杂且丑陋(GUI 基本上只显示来自 Python 的数据,因此需要一个巨大的代理/包装器来围绕它)。而且我认为我仍然需要在某些时间点等待 Python 数据,所以我只是介绍在其他时间点可能出现的死锁情况。
此外,如果我可以从另一个线程安全地访问 MyWidget
,那么所有问题都会消失。与上述相比,引入全局互斥体是更简洁、更短的解决方案。
最佳答案
您可以使用信号/槽机制,但如果 GUI 控件的数量很大,它可能会很乏味。我建议使用单个信号和插槽来控制图形用户界面。发送包含更新 GUI 所需的所有信息的 struct
。
void SomeWidget::updateGUISlot(struct Info const& info)
{
firstControl->setText(info.text);
secondControl->setValue(info.value);
}
如果收件人被删除,您无需担心发出信号。此细节由 Qt
处理。或者,您可以在退出 GUI 线程事件循环后等待线程退出。你需要 register带有 Qt
的结构。
编辑:
根据我从您的扩展问题中读到的内容,您的问题与线程之间的通信有关。尝试使用管道、(POSIX) 消息队列、套接字或 POSIX 信号代替 Qt
信号进行线程间通信。
关于c++ - 如何从其他线程访问QWidget,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21750947/
我是一名优秀的程序员,十分优秀!