如何正确终止GUI应用中的QThread?

5 投票
3 回答
16596 浏览
提问于 2025-04-17 05:10

我尝试在 QThread 类中使用 self.terminate(),也在 GUI 类中使用 self.thread.terminate()。我还尝试在这两种情况下都加上 self.wait()。不过,有两种情况发生:

1) 线程根本没有结束,导致 GUI 界面卡住,等待线程完成。一旦线程结束,GUI 就恢复正常。

2) 线程确实结束了,但同时也让整个应用程序都卡住了。

我还尝试使用 self.thread.exit(),但也没有成功。

为了更清楚,我想在 GUI 中实现一个用户中止按钮,可以随时终止正在执行的线程。

谢谢大家的帮助。

编辑:

这是 run() 方法:

def run(self):
    if self.create:
        print "calling create f"
        self.emit(SIGNAL("disableCreate(bool)"))
        self.create(self.password, self.email)
        self.stop()            
        self.emit(SIGNAL("finished(bool)"), self.completed)

def stop(self):
     #Tried the following, one by one (and all together too, I was desperate):
     self.terminate()
     self.quit()
     self.exit()
     self.stopped = True
     self.terminated = True
     #Neither works

这是 GUI 类中用于中止线程的方法:

def on_abort_clicked(self):
     self.thread = threadmodule.Thread()
     #Tried the following, also one by one and altogether:
     self.thread.exit()
     self.thread.wait()
     self.thread.quit()
     self.thread.terminate()
     #Again, none work

3 个回答

0

我之前遇到过类似的问题,最后是通过使用 pyqtSignalspyqtSlots 来解决的。你可以在你的主窗口类中创建一个 pyqtSignal,并把 aboutToQuit 函数应用到你的 QApplication 实例上。然后,你把这个 aboutToQuit 函数连接到另一个函数,这个函数会发出一个信号给你在另一个线程中的槽函数。这样,你就可以在这个线程中定义一个 stop() 函数,当信号发出时这个函数就会运行。在这种情况下,线程在工作时就不会结束。

主窗口:

class mainSignals(QObject):
    isClosed = pyqtSignal()

class mainwindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(mainwindow, self).__init__()
        self.mainSignal = mainSignals()
        ...
        ...

if __name__ = "__main__":
    # This function runs if the application is closed. 
    # (app.aboutToQuit.connect(windowClose))
    def windowClose():
        window.mainSignal.isClosed.emit() # Emit the signal to the slot in (sepThread)


    app = QApplication(sys.argv)
    app.aboutToQuit.connect(windowClose)
    window = mainwindow()
    window.show()
    sys.exit(app.exec())

分线程:

class sepThread(QRunnable):
    def __init__(self, parent):
        super(sepThread,self).__init__()
        self._parent = parent
        self.mainOpen = True
        self._parent.mainSignal.isClosed.connect(self.stopThread)
        # If the signal was emitted by the Mainapplication 
        # the stopThread function runs and set the mainOpen-attribute to False

    def stopThread(self):
        self.mainOpen = False
    
        
    def run(self):
        while self.mainOpen == True:
            # Do something in a loop while mainOpen-attribute is True
            ...
            ...
0

我做了以下这些事情:

class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    stop_flag = 1
    ...

#=========500 ms class ===================
class Timer500msThread(QThread):
    signal_500ms = pyqtSignal(str) 
    ....
    def timer500msProcess(self):
        if MainWindow.stop_flag == 0 :
            self.timer_500ms.stop()
#==========
#=========Main Window ===================
        
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
MainWindow.stop_flag=0      #this sets the flag to 0 and when the next 500ms triggers the 
                               #the thread ends
print("Program Ending")

6

来自Qt文档关于QThread::terminate的内容:

警告:这个函数很危险,不建议使用。你可以在任何时候终止一个线程,这样可能会导致线程在修改数据的时候被强行停止。这样的话,线程就没有机会自己清理,比如解锁任何被占用的资源等等。简单来说,只有在绝对必要的情况下才使用这个函数。

其实,重新考虑你的线程处理方式会更好,比如可以使用QThread::quit()来通知线程安全地退出,而不是用这种方式强行终止线程。实际上,如果你在线程内部调用thread.exit(),这应该可以实现安全退出,具体还要看你是如何实现run()方法的。如果你愿意分享一下你的线程运行方法的代码,可能能帮助找出为什么它不工作的原因。

撰写回答