본문 바로가기

컴퓨터, IT/프로그래밍

[파이썬] 멀티쓰레드 오류없이 종료하기 (QThread + GUI)

반응형

QThread 를 이용해서 멀티쓰레드를 무한루프를 돌리는 GUI 코드는 GUI 종료시에 오류가 발생할 수 있습니다.

 

멀티쓰레드를 이용한 Worker 클래스의 무한루프를 제어할 수 있는 변수를 사용하는 것이 좋고,

메인 GUI 종료를 할 때 별도의 메소드를 만들어서 오류없이 빠져나갈 수 있도록 구성하는 것이 깔끔합니다.

 

아래 예시를 보면서 설명을 하겠습니다.

 

1. 종료메소드

Worker 클래스가 멀티쓰레드로 구현되는 무한루프이며 self.power 변수가 True 면 작동하게 되어있습니다.

Main 에서 종료를 할 시 Worker.power를 False로 변경하고,

QThread에서 상속된 함수 quit()을 실행하여 멀티쓰레드를 종료하는 과정입니다.

혹시 모르니 QThread.wait(3000)으로 일정 시간동안 대기를 시켜줍니다.

def stop(self):
	self.power = False
	self.quit()
	self.wait(3000)  # 3초 대기 (바로 안꺼질수도)

 

참고로, QThread 안에 terminate 함수도 있습니다만,

가급적이면 플래그를 내리고 (power를 false 시키고) quit을 사용해서 빠져나오는 것이 좋습니다.

 

 

 

2. 멀티쓰레드 종료 과정

 

MainWindow 클래스에서 멀티쓰레드 클래스인 Woker를 self.woker로 선언합니다.

Woker 클래스 내부에는 stop메소드가 이미 정의되어 있습니다.

stop 메소드는 QThread의 종료 메소드 quit()을 실행하게 되어있습니다.

MainWindow가 종료될 때 (GUI 에서 Are you sure to quit 을 묻는 부분),

Woker의 stop()을 실행하게 만들어줍니다.

 

이렇게 하면 파이썬에서 GUI를 종료할 때 이상한 에러메세지 없이

안전하게 종료가 가능합니다.

 

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5 import uic


class Worker(QThread):

    def __init__(self):
        super().__init__()
        self.power = True                           # run 매소드 루프 플래그

    def run(self):
        while self.power:
            if ...:
                print('...')

    def stop(self):
        # 멀티쓰레드를 종료하는 메소드
        self.power = False
        self.quit()
        self.wait(3000)  # 3초 대기 (바로 안꺼질수도)


class MainWindow(QMainWindow, form_class):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

        # thread start
        self.worker = Worker()
        self.worker.start()

    def closeEvent(self, event):
        quit_msg = "Are you sure you want to exit the program?"
        reply = QMessageBox.question(self, 'Message', quit_msg, QMessageBox.Yes, QMessageBox.No)

        if reply == QMessageBox.Yes:
            # 멀티쓰레드를 종료하는 stop 메소드를 실행함
            self.worker.stop()
            event.accept()
        else:
            event.ignore()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    app.exec_()

 

 

 

 

 

 

에러 해결 (https://pixabay.com/images/id-77495/)