简体   繁体   中英

PyQt5: Thread Not Ending? Process finished with exit code -1

Below code runs well and does its job. However, when I exit the GUI, the python file does not finish processing.

When I run through pycharm debug run then force terminate the debug, I get the message "Process finished with exit code -1".

Could anyone help me to find what is causing this error?

from PyQt5 import uic
from PyQt5.QtWidgets import QWidget
from pybithumb import WebSocketManager
from PyQt5.QtCore import QThread, pyqtSignal

class OverViewWorker(QThread):
    data24Sent = pyqtSignal(int, float, int, float, int, int)
    dataMidSent = pyqtSignal(int, float, float)

    def __init__(self, ticker):
        super().__init__()
        self.ticker = ticker
        self.alive = True

    def run(self):
        wm = WebSocketManager("ticker", [f"{self.ticker}_KRW"], ["24H", "MID"])
        while self.alive:
            data = wm.get()
            if data['content']['tickType'] == "MID":
                self.dataMidSent.emit(int(data['content']['closePrice']),
                    ## Deleted
            else:
                self.data24Sent.emit(int(data['content']['closePrice']),
                    ## Deleted

    def close(self):
        self.alive = False

class OverviewWidget(QWidget):
    def __init__(self, parent=None, ticker="BTC"):
        super().__init__(parent)
        uic.loadUi("resource/overview.ui", self)

        self.ticker = ticker
        self.ovw = OverViewWorker(ticker)
        self.ovw.data24Sent.connect(self.fill24Data)
        self.ovw.dataMidSent.connect(self.fillMidData)
        self.ovw.start()

    def fill24Data(self, currPrice, volume, highPrice, value, lowPrice, PrevClosePrice):
        ## Deleted

    def fillMidData(self, currPrice, chgRate, volumePower):
        ## Deleted

    def closeEvent(self, event):
        self.ovw.close()

if __name__ == "__main__":
    import sys
    from PyQt5.QtWidgets import QApplication
    app = QApplication(sys.argv)
    ob = OverviewWidget()
    ob.show()
    exit(app.exec_())

In your code, the QThread.run() method enters a while True loop, which never allows any CPU time to execute the close method and change self.alive to False, therefore that loop never ends even though you emit the close signal from the QWidget.

You are then trying to quit a thread which is still running, and that gives you the -1 return code as your QThread is forcefully killed without finishing its tasks.

If you add the possibility to update the alive parameter from within the loop, you can get out of this issue, but it would need the QThread to access a parameter of the QWidget, which may not be what you want.

Moreover, using QThread.wait() method may help you for synchronizing, as it will forcefully delay the exit of your QWidget until ovw returns from run. Since your -1 return code may just be due to your QApplication exiting moments before the thread finishes, synchronizing the exits will alleviate that.

Here is an example of that based on your code:

from PyQt5 import uic
from PyQt5.QtWidgets import QWidget
from pybithumb import WebSocketManager
from PyQt5.QtCore import QThread, pyqtSignal

class OverViewWorker(QThread):
    data24Sent = pyqtSignal(int, float, int, float, int, int)
    dataMidSent = pyqtSignal(int, float, float)

    def __init__(self, ticker, master):
        super().__init__()
        self.ticker = ticker
        self.master = master
        self.alive = True

    def run(self):
        wm = WebSocketManager("ticker", [f"{self.ticker}_KRW"], ["24H", "MID"])
        while self.alive:
            data = wm.get()
            if data['content']['tickType'] == "MID":
                self.dataMidSent.emit(int(data['content']['closePrice']),
                    ## Deleted
            else:
                self.data24Sent.emit(int(data['content']['closePrice']),
                    ## Deleted

            self.get_alive_from_master()

        # Do here anything you want in the thread before quitting.

    def get_alive_from_master(self):
        self.alive = master.ovw_alive

class OverviewWidget(QWidget):
    def __init__(self, parent=None, ticker="BTC"):
        super().__init__(parent)
        uic.loadUi("resource/overview.ui", self)

        self.ticker = ticker
        self.ovw = OverViewWorker(ticker, self)
        self.ovw.data24Sent.connect(self.fill24Data)
        self.ovw.dataMidSent.connect(self.fillMidData)
        self.ovw_alive = True
        self.ovw.start()

    def fill24Data(self, currPrice, volume, highPrice, value, lowPrice, PrevClosePrice):
        ## Deleted

    def fillMidData(self, currPrice, chgRate, volumePower):
        ## Deleted

    def closeEvent(self, event):
        self.ovw_alive = False
        self.ovw.wait()

if __name__ == "__main__":
    import sys
    from PyQt5.QtWidgets import QApplication
    app = QApplication(sys.argv)
    ob = OverviewWidget()
    ob.show()
    exit(app.exec_())

Qt application exits if last window closed, if there are running threads left, it terminates them. It can be overriden with app.setQuitOnLastWindowClosed(False) . In that case you must call app.quit() on thread finished to terminate application.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM