2014-10-14 2 views
0

Я пытаюсь реализовать программу с несколькими потоками. В окне __init__ главного окна создаются потоки. GUI запускается, а потоки запускаются в фоновом режиме. Проблема в том, что он продолжает терпеть крах. Но если я добавлю/раскомментирую строку с заявлением о печати, программа отлично работает.Несколько QThread продолжают сбой PySide

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() 

Странно, что заявление о печати заставит его остановиться. Что я не замечаю?

+0

Что значит 'он выходит из строя' означает, точно? – aruisdante

+0

Я запускаю этот код в Maya. Это сбой майи. Майя просто закрывает меня без предупреждения. –

ответ

0

Я, наконец, получил его, используя 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() 
+0

Отмечено как ответ. Он не отвечает на вопрос о том, почему код рушился, но этот метод кажется лучше, чем я изначально пытался сделать. –

Смежные вопросы