2017-04-23 204 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