gpt4 book ai didi

python - PyQt 崩溃和线程安全

转载 作者:太空狗 更新时间:2023-10-30 02:30:01 28 4
gpt4 key购买 nike

你好 StackExchange 社区,

首先,你们对我帮助很大,非常感谢。第一次提问:

我目前正在编写一个 PyQt GUI 应用程序,我发现它在 Windows 系统上崩溃了,它还在我家里的机器上给我一个段错误,而它在工作的机器上运行(都是 linux mint 17)。经过一些研究,我意识到我可能创建了一个线程不安全的 GUI,因为我有几个对象相互调用方法。

From another stackoverflow question: GUI widgets may be accessed only from main thread, meaning the thread that calls QApplication.exec(). Access to GUI widgets from any other thread – what you're doing with your calls to self.parent() – is undefined behaviour, in your case this means crashes.

From Qt docs: Although QObject is reentrant, the GUI classes, notably QWidget and all its subclasses, are not reentrant. They can only be used from the main thread. As noted earlier, QCoreApplication::exec() must also be called from that thread.

所以最后,我认为我应该只使用信号槽系统来这样做。

  1. 这是正确的吗?
  2. 这是否仅在函数调用时需要,或者我是否可以在运行时以线程安全的方式从其他对象操作某些对象的字段?例如,我有一个可从多个其他对象访问的选项对象,并且我经常从不同来源更改参数。线程安全还是不安全?

接下来,我在示例代码中重新创建这种线程不安全行为时遇到了问题。 Qt 文档说 QObjects 存在于不同的线程中。这意味着,以下 Qt 应用程序应该是线程不安全的(如果我理解正确的话)。

from PyQt4 import QtGui
import sys

class TestWidget(QtGui.QWidget):
def __init__(self,string):
super(TestWidget,self).__init__()
self.button = QtGui.QPushButton(string,parent=self)
self.button.clicked.connect(self.buttonClicked)

# just to check, and yes, lives in it's own thread
print self.thread()

def buttonClicked(self):
# the seemingly problematic line
self.parent().parent().statusBar().showMessage(self.button.text())
pass
pass

class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow,self).__init__()

Layout = QtGui.QHBoxLayout()
for string in ['foo','bar']:
Layout.addWidget(TestWidget(string))

CentralWidget = QtGui.QWidget(self)
CentralWidget.setLayout(Layout)
self.setCentralWidget(CentralWidget)
self.statusBar()
self.show()
pass
pass

if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
M = MainWindow()
sys.exit(app.exec_())

但它在我的机器上也能正常运行,在 Windows 机器上也能正常运行。

  1. 为什么?这实际上是线程不安全的并且可能会崩溃,但事实并非如此?

谢谢你帮我解决这个问题......

最佳答案

这是正确的吗?

是的,您应该只将信号槽系统用于 q 对象之间的交互。这就是它的本意。

这只是函数调用需要的,还是我可以操作某些对象的字段在运行时以线程安全的方式来自其他对象?

I have a options object that is accessed from multiple other objects...

如果这里的对象是指 Q 对象:

你的options对象应该支持信号槽机制,你可以实现这个从 QObject 派生 options

class Options(QtCore.QObject):
optionUpdated = QtCore.pyqtSignal(object)

def __init__(self):

self.__options = {
'option_1': None
}

def get_option(self, option):
return self.__options.get(option)

def set_option(self, option, value):
self.__options[option] = value
self.optionUpdated.emit(self)

然后所有使用此选项的小部件/对象都应该有一个连接到此信号的插槽。

一个简单的例子:

    options = Options()
some_widget = SomeWidget()
options.optionUpdated.connect(some_widget.options_updated) // Is like you implement the observer pattern, right?

为什么?这实际上是线程不安全的并且可能会崩溃,但事实并非如此?

thread-unsafe 并不意味着“保证会崩溃”,而是“这可能会崩溃”或“很可能会崩溃”。

来自 pyqt API 文档 QObject.thread :

Returns the thread in which the object lives.

勘误表

正如 ekumoro 所指出的,我已经重新检查了我之前关于每个对象离开不同线程的位置,并且......我错了!

QObject.thread 将为每个对象返回不同的QThread 实例QThread 实际上不是线程,只是这些线程的包装器由操作系统提供。

所以代码并没有真正存在多个对象在不同线程中的问题。

为了简单起见,我对您用于演示的代码进行了一些修改:

from PyQt4 import QtGui
import sys

class TestWidget(QtGui.QWidget):
def __init__(self,string):
super(TestWidget,self).__init__()
# just to check, and yes, lives in it's own thread
print("TestWidget thread: {}".format(self.thread()))

class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow,self).__init__()
print("Window thread: {}".format(self.thread()))
Layout = QtGui.QHBoxLayout()
for string in ['foo','bar']:
Layout.addWidget(TestWidget(string))
self.show()

if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
M = MainWindow()
sys.exit(app.exec_())

是的,这会打印:

Window thread: <PyQt4.QtCore.QThread object at 0x00000000025C1048>
TestWidget thread: <PyQt4.QtCore.QThread object at 0x00000000025C4168>
TestWidget thread: <PyQt4.QtCore.QThread object at 0x00000000025C41F8>

演示每个控件都在其自己的线程中。

现在,您有了信号槽机制来处理这种“线程安全”,任何其他方法都不是线程安全的。

关于python - PyQt 崩溃和线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29626948/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com