大家好,StackExchange社区的朋友们:
首先,非常感谢你们给了我很多帮助。这是我第一次提问:
我正在编写一个PyQt GUI应用程序,我发现它在Windows系统上崩溃,同时在我的家用电脑上出现了段错误,而在工作用的电脑(都是Linux Mint 17)上则可以运行。经过一些研究,我意识到我可能创建了一个线程不安全的GUI,因为我有几个对象调用彼此的方法。
来自另一个stackoverflow问题:GUI小部件只能从主线程访问,也就是调用QApplication.exec()的线程。从任何其他线程访问GUI小部件 - 即您通过调用self.parent()进行的操作 - 是未定义的行为,在您的情况下会导致崩溃。
来自Qt文档:虽然QObject是可重入的,但GUI类,特别是QWidget及其所有子类,不可重入。它们只能从主线程中使用。如前所述,必须从该线程中调用QCoreApplication::exec()。
因此,我最终发现我应该只使用信号槽系统。
- 这是正确的吗?
- 这仅适用于函数调用,还是我可以以线程安全的方式从其他对象运行时操纵某些对象的字段?例如,我有一个选项对象,多个其他对象都可以访问它,并且我经常从不同的来源更改其中的参数。是线程安全还是不安全?
接下来,我有一个问题是,我无法在示例代码中重现这个线程不安全的行为。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机器上正常运行。
- 为什么?这真的是线程不安全的,可能会崩溃,但它却没有崩溃吗?
感谢您帮助我解决这个问题...
get_options
函数从options
检索值。因此,如果我的外部对象位于另一个线程中,则执行跨线程函数调用,这被认为是有问题的。现在在您的代码中,在设置值后发出信号,仅通知some_widget
发生了options
的某些变化。或者没有? - grg rsrself.thread()
时创建了一个新的QThread
实例。请记住,QThread
实际上并不是一个线程!它只是一个管理由操作系统提供的线程的包装器。 - ekhumoro