-1

When calling a thread class in PyQt5, the application crashes with error: QThread: Destroyed while thread is still running if I don't add

def __del__(self): 
     self.wait()

After adding the above statement to the thread class, the application runs but stalls until the thread has finished executing (basically making the thread useless). I'm running macOS Catalina 10.15.6, Intel i9, Python 3.7.4. Any way to resolve this? Here is the code (the ui window only has one button in it):

from PyQt5.QtWidgets import QMainWindow
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import QThread, pyqtSignal
import sys, time

class Main(QMainWindow):
    def __init__(self, parent=None):
        super(Main, self).__init__(parent)
        uic.loadUi('main.ui', self)
        self.btn1.clicked.connect(self.run_worker)

    def run_worker(self):
        worker = Worker_thread()
        worker.start()


class Worker_thread(QThread):
    def __init__(self):
        QThread.__init__(self)

    def __del__(self):
         self.wait()

    def run(self):
        time.sleep(10)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    win = Main()
    win.show()
    sys.exit(app.exec_())
pyropeach
  • 13
  • 4
  • Adding `self.wait()` inside `__del__` is a very bad idea. – musicamante Nov 19 '20 at 09:43
  • @musicamante Could you please elaborate as to why? – pyropeach Nov 19 '20 at 14:32
  • There are various reasons, including your case (the whole process gets blocked until finished, which means that you might need to *kill* the application in order to actually exit it, and that's not good). Also, `__del__` might even not be called at all, it's not safe to clean up asynchronous resources like that, and there might be cases for which the python reference is garbage collected while the C++ object has been already destroyed. Read [some](https://stackoverflow.com/q/54770360) [relevant](https://stackoverflow.com/q/10685921) [questions](https://stackoverflow.com/q/6928872). – musicamante Nov 19 '20 at 14:53

1 Answers1

3

The problem is simple: The "worker" variable is a local variable that when its scope ends it is eliminated, in this case the scope is the "run_worker" function. When the "run" method is eliminated, it is not executed in the secondary thread that manages the QThread but in the main thread blocking the GUI.

The solution is to extend its scope, for example by making class attribute:

def run_worker(self):
    self.worker = Worker_thread()
    self.worker.start()

Note: The problem is not OS dependent.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241