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

bra*_*eye 4 python multithreading pyqt thread-safety pycharm

我正在尝试使用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 Code Online (Sandbox Code Playgroud)

当我serialEnabledrun()或中进行读/写操作时发生崩溃ConnDisconn()。我知道PyQt不是线程安全的,变量的错误处理会导致我的类型崩溃,但是我无法理解我的代码出了什么问题。我的想法(可能是错误的)是所有serialThread方法都在同一线程上执行,即使它们连接到gui(主线程)也是如此。错了吗 同样,我从中发出事件,serialThread然后将它们连接到GUI,但这从来没有给我带来问题。

你能看到我犯的错误吗?如果崩溃时没有其他信息,有没有办法调试代码?(我使用PyCharm 2017.1.3)。

ekh*_*oro 5

PyQt是线程安全的,其程度与Qt是线程安全的相同。Qt文档会告诉您他们的API的哪些部分被保证是在什么情况下发生的。

Cross-thread signals are thread-safe, so calling the updatePB method in your example is okay. Your ConnDisconn method is not thread-safe, but that has got nothing to do with PyQt or Qt - it's just a consequence of how you wrote it. The serialEnabled attribute could be read/written by two threads simultaneously, so the behaviour is strictly undefined. A thread-safe way of writing this would be to use a mutex, like so:

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()
Run Code Online (Sandbox Code Playgroud)

(NB: if you're using any kind of IDE or debugger, and you are getting unexpected errors or crashes, your first step in diagnosing the problem should always be to test the code in a standard console. Quite often, the IDE or debugger itself can be the cause of the problem, or may mask error messages comming either from Python or from underlying libraries, such as Qt).