1. ホーム
  2. python

[解決済み] なぜPyQtは情報なしでクラッシュするのですか?(終了コード 0xC0000409)

2022-01-31 04:13:54

質問

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)

を読み書きの際にクラッシュします。 serialEnabledrun() または ConnDisconn() . PyQtがスレッドセーフではないこと、変数の取り扱いを間違えると私のようなタイプのクラッシュが発生することは知っていますが、私のコードのどこが問題なのかがわかりません。私の考えは(多分間違っていますが)、すべての serialThread メソッドは同じスレッドで実行され、GUI(メインスレッド)に接続されている場合も同様です。これは間違っているのでしょうか?同じように、私はイベントを serialThread で、GUIに接続したのですが、それで問題が発生したことはありません。

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

どのように解決するのですか?

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

クロススレッドシグナルはスレッドセーフです。 updatePB メソッドを使用することは問題ありません。あなたの ConnDisconn メソッドはスレッドセーフではありませんが、それはPyQtやQtとは関係なく、単にあなたが書いた方法の結果です。その serialEnabled 属性は同時に2つのスレッドから読み書きされる可能性があり、そのため動作は厳密に不定です。スレッドセーフな書き方としては ミュートス というように。

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のような基礎的なライブラリから来るエラーメッセージを隠してしまうことがよくあります)。