PySide QThread.terminate()导致致命的python错误

时间:2015-01-15 10:12:38

标签: python c++ multithreading qt pyside

我使用的是PySide 1.2.2版,它包含了Qt v4.8框架。我处于这样一种情况,我必须选择让我的应用程序等待QThread我不再需要正常退出(线程很可能会无限期地阻塞),并给予无响应的线程一个优雅句点(几秒钟),然后在其上调用QThread.terminate()。虽然我希望我可以,但是当底层线程仍在运行时,我不能让QThread对象超出范围,因为这会抛出错误“QThread:在线程仍在运行时被销毁”并且几乎​​肯定会导致段错误

请注意,我知道terminating QThreads is dangerous and highly discouraged。我只是想在这里探讨我的选择。

但是当我尝试终止一个线程时,我的应用程序崩溃并出现以下错误:

  

致命的Python错误:释放

时,此线程状态必须是最新的

您可以通过复制/粘贴并运行以下代码来自行尝试:

from PySide import QtCore, QtGui

class Looper(QtCore.QThread):
    """QThread that prints natural numbers, one by one to stdout."""
    def __init__(self, *args, **kwargs):
        super(Looper, self).__init__(*args, **kwargs)
        self.setTerminationEnabled(True)

    def run(self):
        i = 0
        while True:
            self.msleep(100)
            print(i)
            i += 1

# Initialize and start a looper.                                                                      
looper = Looper()
looper.start()

# Sleep main thread for 5 seconds.                                                                    
QtCore.QThread.sleep(5)

# Terminate looper.                                                                                   
looper.terminate()

# After calling terminate(), we should call looper.wait() or listen
# for the QThread.terminated signal, but that is irrelevant for
# the purpose of this example.

app = QtGui.QApplication([])
app.exec_()

如何在Python中正确终止QThreads?

我认为我得到的错误与发布Global Interpreter Lock有关,但我不确定到底出了什么问题,以及如何修复它。

1 个答案:

答案 0 :(得分:2)

似乎错误可能是PySide特有的:用PyQt4运行你的例子根本不会产生任何错误。

至于如何安全地终止QThread的一般问题:它完全取决于你对线程中正在完成的工作有多少控制权。如果它实际上是一个可以定期检查标志的循环,那么解决方案很简单:

class Looper(QtCore.QThread):
    ...         

    def interrupt(self):
        self._active = False

    def run(self):
        i = 0
        self._active = True
        while self._active:
            self.msleep(100)
            print(i)
            i += 1

app = QtGui.QApplication([])

looper = Looper()
looper.finished.connect(app.quit)
looper.start()

QtCore.QTimer.singleShot(3000, looper.interrupt)

app.exec_()

一旦run方法返回,线程将干净地完成,因此您必须找到一些允许这种情况发生的机制。如果你不能这样做(也许是因为在线程中完成的工作基本上不在你的控制范围内),你应该考虑转而使用multiprocessing方法。