多个QThread不断崩溃PySide

时间:2014-10-14 17:39:18

标签: python pyside qthread

我正在尝试使用多个线程实现一个程序。在主窗口的__init__中,创建了线程。 GUI启动,而线程在后台运行。问题是它一直在崩溃。但是如果我用print语句添加/取消注释一行,程序就可以正常工作。

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 个答案:

答案 0 :(得分:0)

我终于通过使用QThreadPool来实现它。它为我管理线程,所以我不必担心尝试访问已被破坏的东西。主要差异:

  • worker类现在继承自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()