Python/PySide: How can i destroy a terminated thread object?

19,835

You're right, your problem is, that your object is not deleted. You delete only the reference self.new_thread. The problem is in this line:

self.new_thread = thread_worker(self)

The reason for this is that the parent self of the thread is alive. As long as parent stays alive, the object self.new_thread is not destroyed. Try something like this:

self.threadParent = QObject()
self.new_thread = thread_worker(self.threadParent)

And now you also delete the parent self.threadParent:

self.new_thread.terminate()
del(self.new_thread)
del(self.threadParent)

Your signals should be disconnected now.

You don't need the following line, because the object self.new_thread has been already deleted after you emit the signal stop_thread_signal:

#self.terminate() # does it works at this place?
Share:
19,835
Igor
Author by

Igor

Updated on June 04, 2022

Comments

  • Igor
    Igor almost 2 years

    I would like to implement a button to stop a thread with a process, it works but not as expected: i can't delete the thread object. (EDIT: The reference to the thread object seems to be deleted, but the signals are not disconnected automatically by deleting the thread object, i can access it anyway via the signal.)

    I have a modul with a class thread_worker and a function for complex processing which is running as process:

    from PySide.QtCore import *
    from PySide.QtGui import *
    import multiprocessing as mp
    import time
    
    # this function runs as a process
    def complex_processing(queue):
        # do something
        ...
    
    class thread_worker(QThread):
        message_signal = Signal(str)
        stop_thread_signal = Signal()
    
        def __init__(self, prozessID, sleepTime, parent=None):
            super(ThreadProzessWorker, self).__init__(parent)
            self.queue = mp.Queue()
            self.process = mp.Process(target=complex_processing, args=(self.queue,))
            self.timeStamp = int(time.time())
    
        def run(self):
            self.process.start()
            self.process.join()
    
        @Slot()
        def stop_process_and_thread(self):
            if self.isRunning():
                self.message_signal.emit("Thread %d is running!" % self.timeStamp)
                if self.process.is_alive():
                    self.process.terminate()
                    self.process.join()      
                self.stop_thread_signal.emit()   
                #self.terminate() # does it works at this place?       
            else:
                self.message_signal.emit("Thread %d is not running!" % self.timeStamp)
    

    I have two buttons in my application to create/run and terminate a thread object.

    ...
    ...
    # Buttons
    self.button_start_thread = QPushButton("Start Thread")
    self.button_start_thread.clicked.connect(self.start_thread)
    self.button_stop_thread = QPushButton("Stop Thread")
    ...
    ...
    @Slot()
    def start_thread(self):
        self.new_thread = thread_worker(self)
        self.button_stop_thread.clicked.connect(self.new_thread.stop_process_and_thread)
        self.new_thread.stop_thread_signal.connect(self.stop_thread)
        self.new_thread.message_signal.connect(self.print_message)
    ....
    ....
    @Slot()
    def stop_thread(self):
        self.new_thread.terminate()
        #self.button_stop_thread.disconnect(self.new_thread)
        del(self.new_thread)
    
    @Slot(str)
    def print_message(self, message):
        print(message)
    ...
    ...
    

    If i start and stop the first thread - it works fine and terminate, but if i klick on the 'Stop'-Button again the output is:

    Thread 1422117088 is not running!
    

    I don't understand it: the object self.new_thread is deleted by del(self.new_thread) or not? How can i access this object if it was deleted? If i start and stop again a new thread, the output is:

    Thread 1422117088 is not running!  # not expected, the thread object is deleted!
    Thread 1422117211 is running!      # expected
    

    Now i do it again (start and stop), the output is:

    Thread 1422117088 is not running!   # not expected, the thread object is deleted!
    Thread 1422117211 is not running!   # not expected, the thread object is deleted!
    Thread 1422117471 is running!       # expected
    

    and so on...

    First question: I don't understand why the old threads are not deleted? Why i can access them? I think it is not good: my application crashes at some point, if there are too many threads (not deleted objects) in the background.

    Second question: I dont't understand why the signals are not disconnected if i delete the object self.new_thread? I don't want to disconnect the signals manually: if i have many signals i can forgot to disconnect some signals.

    Third question: I choose this way to stop a thread with one process. Is there another way to do this better?

    UPDATE:

    The thread object appears to be destroyed:

    del(self.new_thread)
    print(self.new_thread)
    Output: AttributeError: 'MainWindow' object has no attribute 'new_thread'
    

    But my signals are not disconnected!? Here is described that: "A signal-slot connection is removed when either of the objects involved are destroyed." It does not work in my code.