问题描述
我正在使用PySide版本1.2.2,该版本包装了Qt v4.8框架.我处于一种情况下,我必须选择让我的应用程序等待不再需要正常退出的QThread
(很有可能该线程将无限期地阻塞),以及为无响应的线程提供一个宽限期(几秒钟),然后在其上调用QThread.terminate()
.尽管我希望可以,但是当基础线程仍在运行时,我不能让QThread
对象超出范围,因为这将引发错误"QThread:线程仍在运行时销毁"并且几乎肯定会导致段错误. /p>
请注意,我知道终止QThread
是危险的,不鼓励使用.我只是想在这里探索我的选择.
但是,当我尝试终止线程时,我的应用程序崩溃并出现以下错误:
您可以通过复制/粘贴并运行以下代码来自己尝试:
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?
我认为我得到的错误与释放全局解释器锁有关,但是我不确定到底出了什么问题以及如何解决它.
似乎该错误可能特定于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
方法返回,线程将干净地完成,因此您必须找到某种机制来允许这种情况发生.如果您不能这样做(也许是因为线程中完成的工作很大程度上不在您的控制之内),则您可能应该考虑切换到多重处理方法.
I am using PySide version 1.2.2, which wraps the Qt v4.8 framework. I am in a situation where I have to choose between having my application wait for a QThread
that I no longer need to exit normally (it is quite possible that the thread will block indefinitely), and giving the unresponsive thread a grace period (of several seconds), then calling QThread.terminate()
on it. Though I wish I could, I cannot let the QThread
object go out of scope while the underlying thread is still running, since this will throw the error "QThread: Destroyed while thread is still running" and almost surely cause a segfault.
Please note that I am aware that terminating QThread
s is dangerous and highly discouraged. I am just trying to explore my options here.
When I try to terminate a thread however, my application crashes with the following error:
You can try this out yourself by copy/pasting and running the following code:
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_()
How do you properly terminate QThreads in Python?
I reckon that the error I am getting has got something to do with releasing of the Global Interpreter Lock, but I am not sure exactly what is going wrong, and how to fix it.
It seems that the error may be specific to PySide: running your example with PyQt4 does not produce any errors at all.
As for the general issue of how to terminate a QThread
safely: it entirely depends on how much control you have over the work that is being done in the thread. If it is effectively a loop where you can periodically check a flag, then the solution is simple:
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_()
The thread will finish cleanly once the run
method returns, so you must find some mechanism to allow that happen. If you can't do that (perhaps because the work being done in the thread is largely outside of your control), you should probably consider switching to a multiprocessing approach instead.
这篇关于PySide QThread.terminate()导致致命的python错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!