如何确保 QApplication 及其 QThreads 全部关闭

Posted

技术标签:

【中文标题】如何确保 QApplication 及其 QThreads 全部关闭【英文标题】:How to make sure the QApplication and its QThreads are all closed 【发布时间】:2017-07-06 04:50:17 【问题描述】:

下面的代码创建了一个QDialog,它启动了一个QThread,它获得了一个很长的计算函数。 QDialog 的closeEvent() 方法被修改为终止已启动的thread

如何确保thread 仅在完成它正在处理的任务时才终止?使用quit()terminate() 方法停止线程有什么区别? thread 是否应该在主应用程序窗口关闭之前终止?为什么在 Mac OS X 上 Python 进程仍然在活动监视器中列出,即使在主对话框关闭并且线程终止后?

import threading
import Queue as Queue
import datetime

global queue
queue = Queue.Queue()


class Thread(QThread):
    def __init__(self, queue, parent):
        QThread.__init__(self, parent)
        self.queue = queue

    def run(self):
        while True:
            task = queue.get()
            output = task()
            queue.task_done()


def longToCalculate():
    for i in range(30000000):
        i += i
        if not i % 100000:
            print '%s ...still calculating ' % datetime.datetime.now()
    print 'calculation completed'
    return i


class Dialog(QDialog):
    def __init__(self, parent=None):
        super(Dialog, self).__init__(parent)

    def closeEvent(self, event):
        # self.thread.quit()
        self.thread.terminate()
        event.accept()


class Dialog(QDialog):
    def __init__(self, parent=None):
        QDialog.__init__(self, parent)
        self.queue = Queue.Queue()
        self.thread = Thread(queue=self.queue, parent=self)
        self.thread.start()
        queue.put(longToCalculate)

if __name__ == '__main__':
    app = QApplication([])
    dialog = Dialog()
    dialog.show()
    qApp.exec_()

【问题讨论】:

无法保证调用terminate() 会杀死线程(取决于平台)。如果线程没有运行事件循环,则调用 quit() 将无济于事 - 而您的示例不是。但即使是这样,线程也只能在其 run() 方法返回后退出 - 在您的示例中意味着 never (由于无限的while循环)。另外:您还没有提供中断长时间运行的函数的方法,因此线程必须始终等待它完成。没有什么灵丹妙药可以保证杀死一个线程——你必须自己提供退出策略。 【参考方案1】:

这是一个不包含队列的示例代码。

import os, sys
import datetime

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class Thread( QThread ):
    def __init__( self, parent ):

        QThread.__init__( self, parent )

    def run( self ):
        self.longToCalculate()

    def longToCalculate( self ):
        for i in range( 30000000 ):
            i += i

            if ( i % 1000000 == 0 ):
                print( '%s ...still calculating' % QDateTime.currentDateTime().toString() )

        print( 'calculation completed' )
        return i

class Dialog(QDialog):
    def __init__( self, parent = None ):

        QDialog.__init__( self, parent )

        self.thread = Thread( parent = self )
        self.thread.start()

        self.thread.finished.connect( self.threadComplete )

    def threadComplete( self ) :
        QMessageBox.information( self, "Thread complete", "The thread has finished running. This program wil automatically close now." )
        self.close()

    def closeEvent( self, cEvent ) :

        if self.thread.isRunning() :
            QMessageBox.information( self, "Thread running", "The thread is running. You cannot close this program." )
            cEvent.ignore()

        else :
            cEvent.accept()

if __name__ == '__main__':

    app = QApplication( sys.argv )

    dialog = Dialog()
    dialog.show()

    qApp.exec_()

【讨论】:

以上是关于如何确保 QApplication 及其 QThreads 全部关闭的主要内容,如果未能解决你的问题,请参考以下文章

窗口系统如何通知QApplication?

如何将一个 qApplication 的 GUI 嵌入到另一个 qApplication 的主窗口中?

QApplication:如何在 Ctrl-C 上正常关机

如何在不退出 python 脚本的情况下销毁一个 QApplication 然后运行一个新的?

如何使用线程实例化多个 QApplication

如何重新启动 QApplication