How to make QThread quit a process?

42 Views Asked by At

I am a beginner at UI development using PySide6, but due to certain circumstances, I have to design a UI for a program that I have created. In one of the windows of this UI, I have a QObject called worker, which executes a long-running process. I defined the UI for the worker separately in a class called CLD. Here is my init:

class CLD(QWidget):
    back_signal = Signal()

    def __init__(self, question,threshold = 0.85, verbose = True):
        super(CLD, self).__init__()
        self.question = question
        self.threshold = threshold
        self.verbose = verbose

        self.setWindowTitle("CLD Generator")
        
        self.input_area = QTextEdit(self)
        self.input_area.setMinimumHeight(50)
        self.input_area.setMaximumHeight(100)
        self.input_area.setReadOnly(True)
        self.display_area = QTextEdit(self)
        self.display_area.setMinimumHeight(200)
        self.display_area.setReadOnly(True)
        self.user_input = ""

        self.init_ui()

        self.worker = Worker(self, self.question, self.threshold, self.verbose)
        self.thread = QThread()  
        self.worker.moveToThread(self.thread)
        self.worker.finished.connect(self.on_finished)
        self.worker.update_text.connect(self.display_area.append)
        self.worker.get_choice.connect(self.enter_choice)
        self.thread.started.connect(self.worker.generate)
        self.mutex = QMutex()
        self.condition = QWaitCondition()

As you can see, I'm moving the worker to a QThread that I am defining in the CLD class itself. The long-running process is a function in the worker class called generate(). I want to define a "Back" button in the CLD class which when pressed, will abort the execution of the long-running process, and return to the previous window. To that end, I have defined a function like this:

    @Slot(str)
    def on_finished(self, response):
        self.display_area.append(response)
        self.run_button.setEnabled(True)
        self.thread.quit()
        self.thread.wait()

The issue is, when I try to quit(), the thread/long-running process doesn't actually quit. When I use thread.wait(), the UI freezes completely, and no matter how long I wait, it stays the same. When I close the UI by force, I get this error "QThread: Destroyed while thread is still running" which clearly means that the thread wasn't quitting at all. I am thinking that I am doing something wrong here. Maybe the QThread is connected to the main UI so that when I call quit() it doesn't actually quit because the UI is still running? Any advice would be highly appreciated.

Currently in the code, back_signal (which is supposed to be emitted when back button is pressed) is not connected to on_finished(), because I was testing out several things, but under normal circumstances it is connected to on_finished()

1

There are 1 best solutions below

0
dorito On

I solved this issue by abandoning QThreads altogether. I instead used threading module from python to raise an exception in the worker thread. I ensured that I used a separate thread (let's call it monitor thread) to raise the exception. As soon as the Back button is clicked, it emits a signal to the monitor thread which immediately raises an exception in the worker thread. I then call thread.join() to wait for it to terminate. This process is significantly faster than simply calling QThreads.quit() and QThreads.wait(). I am not sure why this is so. If anyone can elaborate on this and validate my approach I would be grateful!