2017-04-23 206 views
4

尽管保存到QThread作为self.lightsThread参考,停止QObjectself.lightsWorker然后开始self.lightsThread再次引起错误PyQt的的QThread:被毁坏,而线程仍在运行

QThread: Destroyed while thread is still running 

停止self.lightsWorker后,必须在QThreadself.lightsThread停止太?如果不是,那么问题似乎是什么?

import sys 
from PyQt4.QtGui import * 
from PyQt4.QtCore import * 
import time 



class Screen(QMainWindow): 
    def __init__(self): 
     super(Screen, self).__init__() 
     self.initUI() 

    def initUI(self): 
     self.lightsBtn = QPushButton('Turn On') 
     self.lightsBtn.setCheckable(True) 
     self.lightsBtn.setStyleSheet("QPushButton:checked {color: white; background-color: green;}") 
     self.lightsBtn.clicked.connect(self.lightsBtnHandler) 

     self.setCentralWidget(self.lightsBtn) 

    def lightsBtnHandler(self): 
     if self.lightsBtn.isChecked(): 
      self.startLightsThread() 
     else: 
      self.stopLightsThread() 

    def startLightsThread(self): 
     print 'start lightsThread' 
     self.lightsThread = QThread() 
     self.lightsWorker = LightsWorker() 
     self.lightsWorker.moveToThread(self.lightsThread) 
     self.lightsThread.started.connect(self.lightsWorker.work) 
     self.lightsThread.start() 


    def stopLightsThread(self): 
     print 'stop lightsThread' 
     self.lightsWorker.stop() 



class LightsWorker(QObject): 
    signalFinished = pyqtSignal() 

    def __init__(self): 
     QObject.__init__(self) 
     self._mutex = QMutex() 
     self._running = True 

    @pyqtSlot() 
    def work(self): 
     while self._running: 
      print 'working' 
      time.sleep(1) 
     self.signalFinished.emit() 

    @pyqtSlot() 
    def stop(self): 
     print 'Stopping' 
     self._mutex.lock() 
     self._running = False 
     self._mutex.unlock() 



app = QApplication(sys.argv) 
window = Screen() 
window.show() 
sys.exit(app.exec_()) 
+0

我的应用程序有同样的问题。然而,这不是真的错误,一切似乎都在起作用。 – Matho

回答

4

以下答案https://stackoverflow.com/a/32138213/7742341停止lightWorker你应该后从线程退出并等待,直到它停止

def stopLightsThread(self): 
    print('stop lightsThread') 
    self.lightsWorker.stop() 
    self.lightsThread.quit() 
    self.lightsThread.wait() 
+0

这个工程!什么是'.wait()'?当不使用'.wait()'时,这个问题中的示例代码不会抛出错误。 – Nyxynyx

+0

在某些情况下,在测试过程中,当我点击按钮的速度太快时,错误被提出是因为线程未完成,然后我尝试重新启动它 – Luchko

2

我不得不面对C++相同的问题,但问题是相同的。

问题是,当关联的线程仍在运行时,您的QThread实例被删除。这可能是非常危险的,因为线程代码的执行会被中断,并保证线程已准备好被删除。

例如:

  • 一个线程控制
  • 一个的ressource在该对象的析构释放(显式或使用的QObject母体时implicilty喜欢的对象(工人)的执行,并且寿命时间/子系统)
  • 由于线程执行被中断时,该对象将不被删除

它导致内存泄漏和的ressource泄漏。

在你的代码中,worker停止了,但不是工作线程。我不是蟒蛇专家,但它似乎也是你的工人对象已停止但未被删除。

,正确停止工作者和线程,你应该:

  • 将消息发送给你的工人告诉它“停止工作”
  • 问你的线程退出:它会发布一个“退出“消息将在工人执行
  • 等待之后处理您的线程的线程停止

的最后一步是optionnal:如果线程和工人不同意蒙山ressources其他的对象,你可能不需要等待他们完成,只是忘记他们。

唯一的解决方法是在退出应用程序之前应正确停止所有线程:在应用程序退出之前,应等待当前所有正在运行的线程停止。

对于简单的任务,您还应该考虑使用QtConcurrent框架。

+0

感谢这项工作,使用Luchko发布的代码。在线程退出'self.lightsThread.quit()'后,我的代码不再抛出错误。我假设'self.lightsThread.wait()'是用于等待线程停止的,如果是的话,为什么不把错误发生在我的示例代码中呢? – Nyxynyx

+1

根据Qt文档,“退出”将事件发布到线程,告诉它停止处理。该事件将在下一个线程的事件循环中处理。 “等待”是等待线程停止。 – Aurelien