web-dev-qa-db-ja.com

情報なしでPyQtがクラッシュするのはなぜですか? (終了コード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()serialEnabledを読み書きすると、クラッシュします。 PyQtはスレッドセーフではなく、変数の処理を誤ると私の型がクラッシュすることは知っていますが、コードの何が問題なのか理解できません。私の考え(おそらく間違っている)は、すべてのserialThreadメソッドが、GUI(メインスレッド)に接続されている場合でも、同じスレッドで実行されるというものです。それは間違っていますか?同様に、serialThreadからイベントを発行し、それらをGUIに接続しましたが、問題が発生することはありませんでした。

私が犯した間違いがわかりますか?他の情報なしでクラッシュした場合にコードをデバッグする方法はありますか? (私はPyCharm 2017.1.3を使用しています)。

4
brazoayeye

PyQtは、Qtがスレッドセーフであるのと同じ程度にスレッドセーフです。 Qtのドキュメントでは、APIのどの部分がそうなることが保証されているか、どのような状況であるかがわかります。

クロススレッドシグナルはスレッドセーフであるため、例のupdatePBメソッドを呼び出しても問題ありません。あなたのConnDisconnメソッドはスレッドセーフではありませんが、それはPyQtやQtとは何の関係もありません-それはあなたがそれをどのように書いたかの結果です。 serialEnabled属性は、2つのスレッドによって同時に読み取り/書き込みが可能であるため、動作は厳密に定義されていません。これを書くスレッドセーフな方法は、次のように 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など)。

5
ekhumoro