Before asking the question, I am aware of people having similar problems and reviewed similar questions, but I did not find the answer. I have tried to follow the example from here to do proper threading on PyQt. I did an example from here, it works well. However, I want a slight modification. I wrote my own class that need to run on a thread without me having to do all of the boilerplate code, like this: def task_to_run(self) ... # a long task that I want to run on a thread worker = JZWorker(self.task_to_run, None, "Name") worker.start() and this is the class that I have built from PySide6.QtCore import QObject, QThread, Signal from loguru import logger class Worker(QObject): finished = Signal() def __init__(self, task, finished_callback, name = "") -> None: super().__init__() self._task = task self._finished = False self._name = name or f"JZWorker-{self._task.__name__}" if finished_callback: self.finished.connect(fin_cb) self.finished.connect(self._on_finished) def run(self) -> None: logger.debug(f"Running separate task in a JZWorker thread: {self._name}") try: self._task() except Exception as ex: logger.exception(f"Error in worker thread {self._name}: {ex}") self.finished.emit() def _on_finished(self) -> None: self._finished = True def is_finished(self) -> bool: return self._finished class JZWorker(QObject): """ JZWorker is a class that can be used to run a non-blocking task in a separate thread without having to do all of the boilerplate code """ finished = Signal() def __init__( self, task, fin_cb = None, name = "") -> None: super().__init__() self._thread = QThread() self._worker = Worker(task, fin_cb, name) self._worker.moveToThread(self._thread) self._thread.started.connect(self._worker.run) self._worker.finished.connect(self._thread.quit) self._worker.finished.connect(self._worker.deleteLater) self._worker.finished.connect(self.finished) self._thread.finished.connect(self._thread.deleteLater) # self._worker.finished.connect( # lambda: logger.warning(f"Worker thread {self._worker._name} finished")) # self._thread.finished.connect( # lambda: logger.error(f"Thread for worker {self._worker._name} finished")) def start(self) -> None: """ Starts the thread and runs the task in a separate thread. This is a non-blocking call. """ self._thread.start() The issue is, that even if the thread is 100% finished, the finished signal of self._thread from JZWorker is never emitted. However, uncommenting the line below, does stop my app from crashing when set worker = None, but the _thread.finished signal is still never emitted. I assume it has to do something with reference to worker still existing so that the garbage collector doesnt collect it, but I am not sure. self._thread.finished.connect(lambda: logger.error(f"Thread for worker {self._worker._name} finished")) I am analzying an example in the page that was provided and there is no answer that I can find. Continue reading...