QThread start() not executing?

36 views Asked by At

I am trying to execute some functions in the background of an PyQt5 application. The print statement in run() does not print when thread.start() is called. I think I am misunderstanding how threads work.

from PyQt5.QtCore    import pyqtSignal,   QObject,     QThread,     QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys, time

class GenericWorker(QObject):
    started  = pyqtSignal()
    finished = pyqtSignal()
    error    = pyqtSignal(Exception)

    def __init__(self, func, *args, **kwargs):
        super().__init__()
        self.func   = func
        self.args   = args
        self.kwargs = kwargs

    def run(self):
        print("Run function executing.")
        try:
            self.func(*self.args, **self.kwargs)
        except Exception as e:
            self.error.emit(e)
        finally:
            self.finished.emit()

class ParentClass:
    def __init__(self, main_app):
        pass

    def parent_function(self):
        print("Parent function.")

    def start_thread(self, func, *args, **kwargs):
        thread = QThread()
        worker = GenericWorker(func, *args, **kwargs)
        worker.moveToThread(thread)

        # create signals
        thread.started.connect(worker.run)
        worker.finished.connect(thread.quit)
        worker.finished.connect(worker.deleteLater)
        thread.finished.connect(thread.deleteLater)
        worker.error.connect(self.handle_worker_error)

        # store thread references, prevent premature garbage collection
        if not hasattr(self, '_threads'):
            self._threads = []
        self._threads.append(thread) 

        # cleanup reference upon thread completion to avoid memory leak
        thread.finished.connect(lambda: self._threads.remove(thread))

        # begin
        thread.start()
    
    def handle_worker_error(self, e):
        print(f"Error occurred: {e}")

class ChildClass(ParentClass):
    def __init__(self, main_app):
        super().__init__(main_app)

    def functionality(self):
        # launch threads for each function
        print("Starting threads.\n")
        self.start_thread(self.parent_function)
        self.start_thread(self.child_function)

    def child_function(self):
        print("Child function.")

class MainApplication(QMainWindow):
    def __init__(self):
        super().__init__()
        test = ChildClass(self)
        test.functionality()

# SEQUENCE OF EVENTS
if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.main = MainApplication()
    app.main.show()
    sys.exit(app.exec_())

If lambda functions are used instead, i.e.:

thread.started.connect(lambda: worker.run())
worker.finished.connect(lambda: thread.quit())
worker.finished.connect(lambda: worker.deleteLater())
thread.finished.connect(lambda: thread.deleteLater())
worker.error.connect(lambda: self.handle_worker_error())

Then all statements are printed. If time.sleep(0.1) is placed after thread.start(), all statements will again be printed. Why is this?

0

There are 0 answers