为什么 PyQt 会在没有信息的情况下崩溃? (退出代码 0xC0000409)

Why does PyQt crashes without information? (exit code 0xC0000409)

我正在尝试使用 PyQt 开发软件,但我经常遇到没有调试信息(只有退出代码 0xC0000409)的软件崩溃。我用的是QThread,我写的系统是这样的:

class serialThreadC(QThread):
    updateOutBox = QtCore.pyqtSignal(str)
    updateStatus = QtCore.pyqtSignal(int)

    def __init__(self):
        super(serialThreadC, self).__init__()
        self.ser = False
        self.state = 0
        self.serialEnabled = False

    def run(self):
        while True:
            if self.state == -3 or self.state == -2:
                if self.SerialEnabled:
                    self.updatePB(20)
            elif self.state == 0:
                if self.serialEnabled:
                    self.updatePB(20)

    def ConnDisconn(self):
        self.serialEnabled = not self.serialEnabled

    def updatePB(self, stat):
        self.state = stat
        self.updateStatus.emit(self.state)

serialThread = serialThreadC()
serialThread.start()

## sw is a QDialog already loaded
serialThread.updateOutBox.connect(sw.updateOutBox)
serialThread.updateStatus.connect(sw.updateStatus)

sw.PB_ConnDisconn.clicked.connect(serialThread.ConnDisconn)

我在 run()ConnDisconn() 中 read/write serialEnabled 时发生崩溃。我知道 PyQt 不是线程安全的,错误的变量处理会导致我的类型崩溃,但我不明白我的代码有什么问题。我的想法(可能是错误的)是所有 serialThread 方法都在同一个线程上执行,如果它们连接到 gui(主线程)也是如此。那是错的吗?以同样的方式,我从 serialThread 发出事件并将它们连接到 GUI,但这从来没有给我带来问题。

你能看出我犯的错误吗?如果在没有其他信息的情况下发生崩溃,有没有办法调试代码? (我用的是PyCharm2017.1.3)

PyQt 的线程安全程度与 Qt 的线程安全程度相同。 Qt 文档会告诉您他们的 API 的哪些部分保证如此,以及在什么情况下如此。

跨线程信号是线程安全的,所以在你的例子中调用updatePB方法是可以的。您的 ConnDisconn 方法不是线程安全的,但这与 PyQt 或 Qt 无关 - 这只是您编写方法的结果。 serialEnabled 属性可以同时被两个线程 read/written,因此行为是严格未定义的。一种线程安全的写法是使用 mutex,像这样:

class serialThreadC(QThread):
    updateOutBox = QtCore.pyqtSignal(str)
    updateStatus = QtCore.pyqtSignal(int)

    def __init__(self):
        super(serialThreadC, self).__init__()
        self.ser = False
        self.state = 0
        self._mutex = QMutex()
        self.serialEnabled = False   

    def ConnDisconn(self):
        self._mutex.lock()
        self.serialEnabled = not self.serialEnabled
        self._mutex.unlock()

    def run(self):
        while True:
            if self.state == -3 or self.state == -2:
                self._mutex.lock()
                if self.serialEnabled:
                    self.updatePB(20)
                self._mutex.unlock()
            elif self.state == 0:
                self._mutex.lock()
                if self.serialEnabled:
                    self.updatePB(20)
                self._mutex.unlock()

(注意:如果您使用任何类型的 IDE 或调试器,并且遇到意外错误或崩溃,诊断问题的第一步应该始终是在标准中测试代码控制台。通常,IDE 或调试器本身可能是问题的原因,或者可能掩盖来自 Python 或底层库(例如 Qt)的错误消息。

我将所有 float 变量设置为 int 值并且有效

之前


var1 = 10.0

var2 = 26.0

之后


var1 = 10

var2 = 26