2017-10-12 10 views
1

私はPyQtを使ってソフトウェアを開発しようとしていますが、デバッグ情報(終了コード0xC0000409のみ)なしでソフトウェアがクラッシュすることがよくあります。私はQThreadを使用している、と私は、このようなシステムを書いた:情報なしでPyQtがクラッシュするのはなぜですか? (終了コード0xC0000409)

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を使用しています)。

+1

端末から実行しようとしましたか? – eyllanesc

+0

それは本当です!ターミナルで私はクラッシュの原因があります:|そして、私は情報がないコードをデバッグするために8時間のように無駄です... その場合、私が与えた2つの同様の関数updatePB(self、stat)とupdatePB(self)の過負荷をPythonが理解できないようです私はそれを呼び出すときに1の代わりに2つのパラメータ。 – brazoayeye

答えて

1

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() 

(NB:あなたはIDEやデバッガの任意の種類を使用している、とあなたが予期しないエラーやクラッシュを取得している場合は、あなたの非常に多くの場合、IDEやデバッガ自体が問題の原因となることがあります。また、Pythonや基になるライブラリからのエラーメッセージをマスクすることもあります。 Qt)。

+0

私はポイントを取得しません。あなたは 'ConnDisconn(self)'が 'serialThread'とは別のスレッドであると言いましたので(ConnDisconnはGUIシグナルに接続されています)、同じことが' sw.updateStatus'にある必要があります糸)。 'sw.updateStatus'I' MyButton.setText()'では、この操作は許可されていますか?さらに、異なるスレッドを使用して同時に変数を読み取ることも禁じられていますか? @Brazoayeye。 – brazoayeye

+0

私は 'ConnDisconn'が別のスレッドに入っているとは言いませんでした(それはメインスレッドにあり、メインスレッドによって呼び出されていません)。しかし、 'updatePB'はスレッドセーフであることが保証されているクロススレッド信号を出力するので、' updatePB'は大丈夫です。ですから、直接の結果として、 'setText()'を呼び出すことは安全です。これはPyQtのすべての標準的なものであり、そこには数十もの類似の質問があります。 *複数のスレッドによって*何かを読み書きすることは決して禁じられていません - それが問題全体です! (それがミューテックスの目的です)。 @brazoayeye。 – ekhumoro

+0

しかし、あなたの特定の例では、mutexはおそらく残念ですが、 'serialEnabled'(つまりメインスレッド)を変更するスレッドが1つしかないので、追加する必要があります。だからあなたのサンプルコードは大丈夫ですが、100%厳密には正しいとは言えません。あなたのコードを修正する限り、私の答えの中で最も重要な部分は、おそらく底のノートです。残りの部分はあなたが尋ねたより一般的な質問に答えるだけです。 – ekhumoro

関連する問題