2017-10-12 1 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가 thread-safe가 아니며 잘못된 변수 처리가 내 유형의 충돌을 일으킨다는 것을 알고 있지만 내 코드에 무엇이 잘못된 것인지 이해할 수 없다. 내 생각은 (아마도 잘못된) 모든 serialThread 메서드는 동일한 스레드에서 실행되며, GUI (메인 스레드)에 연결되어있는 경우에도 마찬가지입니다. 틀렸어? 같은 방식으로, 나는 serialThread에서 이벤트를 내보내고 GUI에 연결했지만 결코 문제가되지 않았습니다.

내가 실수 한 것을 볼 수 있습니까? 다른 정보없이 충돌이 발생하면 코드를 디버그 할 수 있습니까? (저는 PyCharm 2017.1.3을 사용합니다).

+1

터미널에서 실행 해 보았습니까? – eyllanesc

+0

그건 사실이야! 맨끝에서 나는 충돌의 원인이있다 : | 그리고 정보가없는 코드를 디버깅하는 데 8 시간을 낭비합니다 ... 이 경우 python은 두 개의 유사한 함수 updatePB (self, stat)와 updatePB (self)의 오버로드를 이해할 수없는 것 같습니다. 내가 그것을 부를 때 2 대신 1 매개 변수. – brazoayeye

답변

1

PyQt는 Qt가 스레드로부터 안전하다는 것과 같은 정도로 스레드로부터 안전합니다. Qt 문서는 API의 어느 부분이 어떤 상황에서 그렇게 보장되는지 알려줄 것입니다.

크로스 스레드 신호는 스레드로부터 안전하므로 예제의 메서드를 호출해도 문제가 없습니다. ConnDisconn 메서드는 스레드로부터 안전하지는 않지만 PyQt 또는 Qt와는 아무런 관련이 없습니다. 어떻게 작성했는지에 따라 달라집니다. serialEnabled 속성은 두 스레드가 동시에 읽고 쓸 수 있으므로 동작은 엄격히 정의되지 않습니다. 이 글을 쓰는의 스레드 안전한 방법으로 이렇게처럼 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 (자기)가'serialThread'와는 다른 쓰레드라고 말했기 때문에 (ConnDisconn은 GUI 신호에 연결되어 있습니다.) 'sw.updateStatus'에 대해서도 마찬가지입니다. 실). 'sw.updateStatus'에서'MyButton.setText()'는이 작업을 허용합니까? 그리고 다른 스레드를 사용하여 변수를 동시에 읽는 것도 금지됩니까? – brazoayeye

+0

@brazoayeye. 나는'ConnDisconn'이 다른 스레드에 있다는 것을 말하지 않았습니다. (그것은 메인 스레드에 있고 메인 스레드에 의해 호출됩니다.) 그러나'updatePB'는 thread-safe 신호 (Qt에 의해)가 보장 된 크로스 스레드 신호를 방출하기 때문에 괜찮습니다. 그래서 그렇습니다. 바로 그 결과로'setText()'를 호출하는 것이 안전합니다. 이것은 PyQt의 모든 표준적인 내용이며, 이에 관해 수십 가지 유사한 질문이 있습니다. * 쓰레드가 여러 스레드에 의해 * 읽거나 쓰는 것이 절대 금지되지 않습니다 - 그것이 모든 문제입니다! (뮤텍스가 그 것이다.) – ekhumoro

+0

@brazoayeye. 그래도 특정 예제에서는 뮤텍스가 과장 될 가능성이 높습니다. 왜냐하면 (직렬 연결) (즉, 메인 스레드)을 수정하는 스레드가 하나 밖에 없기 때문입니다. 그래서 예제 코드는 100 % 정확하지는 않지만 괜찮아 보입니다. 귀하의 코드를 수정하는 한, 내 대답의 가장 중요한 부분은 아마 하단에 메모입니다. 나머지는 당신이 물어 본보다 일반적인 질문들에 답하려고합니다. – ekhumoro