如何正确地从GUI程序中终止一个Q线程?

5 人关注

我试着在QThread类中使用 self.terminate() ,也在GUI类中使用 self.thread.terminate() 。我还试着在这两种情况下放入 self.wait() 。然而,有两种情况会发生。

1)线程根本没有终止,GUI冻结了,等待线程结束。一旦线程结束,GUI就会解冻,一切恢复正常。

2)该线程确实终止了,但同时它冻结了整个应用程序。

我还试着用 self.thread.exit() 。没有喜悦。

为了进一步澄清,我正试图在GUI中实现一个用户中止按钮,它将在任何时间点终止线程的执行。

提前感谢。

EDIT:

Here is the run() method:

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
    
4 个评论
注意:self.terminate ===(self.terminated = true),仅此而已。对于99%的实现。
谢谢,但这并不能真正帮助解决这个问题。
只有一种方法可以安全地终止线程--让它完成所有任务。要做到这一点,你必须在执行硬任务之前检查thread.terminated。
好吧,这当然不是我在寻找的东西。
python
multithreading
qt
pyqt
Bo Milanovich
Bo Milanovich
发布于 2011-10-28
3 个回答
docsteer
docsteer
发布于 2022-03-21
已采纳
0 人赞同

来自Qt文档的QThread::terminate。

警告 :这个功能是危险的,不鼓励使用它。该 线程可以在其代码路径中的任何一点被终止。线程可以在 在修改数据的时候被终止。线程没有机会 清理自己,解锁任何持有的互斥等等。简而言之,只有在绝对必要时才使用 这个函数只有在绝对必要时才使用。

重新思考你的线程策略可能是个更好的主意,比如你可以使用QThread::quit()来发出信号让线程干净地退出,而不是试图让线程以这种方式终止。实际上,从线程内部调用thread.exit()应该可以做到这一点,这取决于你是如何实现run()的。如果你愿意分享你的线程运行方法的代码,这可能会暗示它为什么不工作。

嗯。我想 self.create() 的方法是线程中最耗时的方法?一般来说,你在里面要做的是类似 while not self.terminated() { do slow operation parts.. } 的事情。不幸的是,我不太了解Python,但看起来有一个线程教程 here 这可能有助于
我也试过这样做。它碰巧起了点作用(GUI不会冻结,但线程也不会终止)。然而,最奇怪的事情刚刚发生。我删除了线程中所有的 def stop(self) 和GUI中的 def on_abort_clicked(self) 代码,并重新编写了它。我简单地把 self.terminate() 放在线程的 stop() 函数中,在GUI类中做了 self.thread.stop() 。这就像一个魅力十足的工作。AFAIK,这是我尝试的第一件事,之前并没有工作。我可能错过了什么。
user14853305
user14853305
发布于 2022-03-21
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")
    
Robert
Robert
发布于 2022-03-21
0 人赞同

我有一个类似的问题,并通过使用 pyqtSignals pyqtSlots 解决了它。 你可以在你的MainWindow-class中创建一个 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())

sepThread:

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):