多个QThread导致PySide崩溃
我正在尝试实现一个有多个线程的程序。在主窗口的__init__
方法里,我创建了这些线程。程序的界面会启动,同时线程在后台运行。问题是程序总是崩溃。不过,如果我添加或取消注释一行打印语句,程序就能正常工作。
class TestThreadingWin(QtGui.QMainWindow):
def __init__(self, parent=rsui.getMayaMainWindow()):
''' Constructor '''
super(TestThreadingWin, self).__init__(parent)
self.setWindowTitle('Test Threading')
self.centralWidget = QtGui.QPlainTextEdit()
self.setCentralWidget(self.centralWidget)
self.centralWidget.appendPlainText("test")
numThreads = 7
self._threads = []
for i in range(numThreads):
#print self._threads # <-- Uncomment this line, and it works?!
testThread = QtCore.QThread()
# Keep a reference to the thread object or it will be deleted when
# it goes out of scope, even if it has not finished processing.
self._threads.append(testThread)
worker = TestThreadWorker(i)
worker.moveToThread(testThread)
worker.finishedProcessing.connect(self.updateStuff)
worker.finishedProcessing.connect(testThread.quit)
testThread.started.connect(worker.doStuff)
testThread.finished.connect(self.deleteThread)
testThread.start()
QtCore.QCoreApplication.processEvents()
print 'done creating all threads'
def deleteThread(self):
""" Destroy the thread object and remove the reference to it from the
self._threads list. """
print 'delete thread'
threadToDelete = self.sender()
threadIndex = self._threads.index(threadToDelete)
del self._threads[threadIndex]
threadToDelete.deleteLater()
def updateStuff(self, message):
self.centralWidget.appendPlainText(message)
class TestThreadWorker(QtCore.QObject):
finishedProcessing = QtCore.Signal(str)
def __init__(self, num):
super(TestThreadWorker, self).__init__()
self._num = num
def doStuff(self):
time.sleep(1)
choiceList = ['cat', 'bat', 'hat', 'tissue', 'paper', 'qwerty', 'mouse']
stuff = random.choice(choiceList)
stuff2 = '{0} {1}'.format(self._num, stuff)
self.finishedProcessing.emit(stuff2)
def openThreadingWin():
'''This ensures that only one instance of the UI is open at a time.'''
global testingThreadingWin
try:
testingThreadingWin.close()
testingThreadingWin.deleteLater()
except: pass
testingThreadingWin = TestThreadingWin()
testingThreadingWin.show()
很奇怪,为什么一条打印语句能让程序不崩溃。我是不是漏掉了什么?
1 个回答
1
我终于通过使用 QThreadPool 让它工作了。这个工具会帮我管理线程,所以我不需要担心去访问那些已经被销毁的东西。主要的不同点有:
- 现在工作类同时继承自 QtCore.QObject 和 QtCore.QRunnable。(它必须继承自 QObject 才能发出信号。)这两个父类的
__init__
函数都必须被调用,否则程序会崩溃。 - 不再需要额外的代码来设置连接,以确保线程在完成后会被销毁。
- 不再需要代码来保持对线程的引用,或者在线程被销毁时删除这些引用。
这是新的代码:
class TestThreadPoolWin(QtGui.QMainWindow):
def __init__(self, parent=rsui.getMayaMainWindow()):
''' Constructor '''
super(TestThreadPoolWin, self).__init__(parent)
self.setWindowTitle('Test Threading')
self.centralWidget = QtGui.QPlainTextEdit()
self.setCentralWidget(self.centralWidget)
self.centralWidget.appendPlainText("test")
numThreads = 7
threadPool = QtCore.QThreadPool.globalInstance()
for i in range(numThreads):
runnable = TestRunnableWorker(i)
runnable.finishedProcessing.connect(self.updateStuff)
threadPool.start(runnable)
print 'done creating all threads'
def updateStuff(self, message):
self.centralWidget.appendPlainText(message)
class TestRunnableWorker(QtCore.QObject, QtCore.QRunnable):
finishedProcessing = QtCore.Signal(str)
def __init__(self, num, parent=None):
# Be sure to run the __init__ of both parent classes, or else you will
# get a crash.
QtCore.QObject.__init__(self, parent)
QtCore.QRunnable.__init__(self)
self._num = num
def run(self):
time.sleep(1)
choiceList = ['cat', 'bat', 'hat', 'tissue', 'paper', 'qwerty', 'mouse']
stuff = random.choice(choiceList)
stuff2 = '{0} {1}'.format(self._num, stuff)
self.finishedProcessing.emit(stuff2)
def openThreadPoolWin():
'''This ensures that only one instance of the UI is open at a time.'''
global testingThreadPoolWin
try:
testingThreadPoolWin.close()
testingThreadPoolWin.deleteLater()
except: pass
testingThreadPoolWin = TestThreadPoolWin()
testingThreadPoolWin.show()