简体   繁体   中英

'QThread: Destroyed while thread is still running' on quit

I'm trying to find a way to quit my app properly. When I exit, I get an error saying QThread: Destroyed while thread is still running . I have a thread for feeding output to a QTextBrowser . What should be the proper way to exit? Here's what I've got:

class LogReceiver(QtCore.QObject):
    mysignal = QtCore.Signal(str)

    def __init__(self, queue, *args, **kwargs):
        QtCore.QObject.__init__(self, *args, **kwargs)
        self.queue = queue

    def run(self):
        while True:
            text = self.queue.get()
            self.mysignal.emit(text)

if __name__ == '__main__':
    queue = Queue()
    thread = QtCore.QThread()
    my_receiver = MyReceiver(queue)

    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()

    my_receiver.mysignal.connect(window.append_text)
    my_receiver.moveToThread(thread)
    thread.started.connect(my_receiver.run)
    thread.start()

    sys.exit(app.exec_())

Should thread somehow be terminated upon exit? Note that self.queue.get() blocks and waits for text.

Thanks

You need to re-structure the while loop so that it doesn't block uncondtionally.

You can do this with a simple flag and a timeout:

    def run(self):
        self.active = True
        while self.active:
            try:
                text = self.queue.get(timeout=1.0)
                self.mysignal.emit(text)
            except Empty:
                continue

So now the queue won't block indefinitely, and the flag will be checked once a second to see if the loop should be exited.

EDIT :

Here's a working example based on your code:

import sys
from queue import Queue, Empty
from PySide import QtCore, QtGui

class LogReceiver(QtCore.QObject):
    mysignal = QtCore.Signal(str)

    def __init__(self, queue, *args, **kwargs):
        QtCore.QObject.__init__(self, *args, **kwargs)
        self.queue = queue

    def run(self):
        self.active = True
        while self.active:
            try:
                text = self.queue.get(timeout=1.0)
                self.mysignal.emit('text')
            except Empty:
                continue
        print('finished')

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.queue = Queue()
        self.thread = QtCore.QThread(self)
        self.receiver = LogReceiver(self.queue)
        self.receiver.moveToThread(self.thread)
        self.thread.started.connect(self.receiver.run)
        self.thread.start()

    def closeEvent(self, event):
        print('close')
        self.receiver.active = False
        self.thread.quit()
        self.thread.wait()

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    window = MainWindow()
    window.show()

    sys.exit(app.exec_())

Try:

# previous code here
thread.start()
app.exec_()

thread.terminate()
thread.wait()
sys.exit(0)

Basically when exec_() finishes ( QApplication is closed ex. by closing the window) you force the thread to terminate and wait() for it to cleanup. If your thread has an event loop you can call quit() instead of terminate() . terminate() is generally not a good idea see: here .

The more desirable approach would be to put a flag in run() method ex.

while !flag:
    do stuff

and change main to:

app.exec_()
flag = True
thread.wait()
sys.exit(0)

Where flag is a global variable. QThread terminates itself when run() method finishes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM