QThread Problem

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
patrice079
User
Beiträge: 13
Registriert: Sonntag 15. April 2012, 13:22

Hallo,

ich habe ein kleines Threading Problem in PyQt4 und würde mich sehr über einen Tip freuen. Ich habe eine etwas langwierige Berechnung in 2 Threads ausgelagert. Die starte ich aus meiner Gui heraus in einem weiteren QThread:

Code: Alles auswählen

class AnyThread(QThread):
  def __init__(self, parent=None):
    QThread.__init__(self,parent)
    
  def run(self):
    #In anything werden zwei Tasks gethreaded
    self._result = AnyModule.anything() 
        
  def getResult(self):
    return self._result
  

... in Gui ...
self.ctimer = QTimer()

self.startProgressBar()
thread = AnyThread()
thread.start()
#1. thread.wait()
thread.finished.connect(self.stopProgressBar)
#2. thread.wait()
self.result = thread.getResult()
nur der Vollständigkeit halber:

Code: Alles auswählen

  def startProgressBar(self):
    self.progressBar.show()
    self.progressBar.setValue(0)
    self.ctimer.start(50)
    
    
  def updateProgressBar(self):
    bla bla
    
    
  def stopProgressBar(self):
    print "stopProgressBar"
    self.ctimer.stop()
    self.progressBar.hide()
Das Problem ist nun das thread.wait(). Lasse ich es ganz weg tut im Prinzip alles so wie ich es gerne hätte, stürzt aber nach dem Thread ab mit:
"QThread: Destroyed while thread is still running"
Kommentiere ich das erste thread.wait() nicht aus beginnt die ProgressBar erst nach dem Thread und hört nicht mehr auf, verwende ich das 2. thread.wait() läuft der Thread durch und stopProgressBar wir aufgerufen danach, die Progressbar wird aber niemals sichtbar.

Für einen Hinweis der mir Hilft meine Verständnislücke zu füllen vielen Dank im Voraus.
lunar

@patrice079: Die Fehlermeldung ist ziemlich eindeutig: Das "QThread"-Objekt wird gelöscht, während der zugehörige Thread noch läuft. Warum das ausgerechnet in Deinem Code passiert, lässt sich mit den gezeigten Schnippseln kaum sagen. Zeige ein vollständiges, aber minimales Beispiel, mit dem wir das Problem reproduzieren können.
patrice079
User
Beiträge: 13
Registriert: Sonntag 15. April 2012, 13:22

Ich habe mir eine Progressbar selbst definiert:

Code: Alles auswählen

class LFQProgressBar(QProgressBar):
  def __init__(self, parent=None):
    super(QProgressBar, self).__init__(parent)
    print "Initialize LFQProgressBar"
    self.sign = 1
    self.progressValue = 0
    self.timer = QTimer()
    QObject.connect(self.timer, SIGNAL("timeout()"), self.update)
    
    
  def start(self):
    print "start progressbar"
    self.timer.start(250)
    self.show()
    self.progressValue = 0
    self.setValue(0)
    
  def update(self):
    print "update progressbar"
    if self.value() >= 100:
      self.sign = -1
    elif self.value() <= 0:
      self.sign = 1
    self.progressValue += self.sign*5
    self.setValue(self.progressValue)
  
  def stop(self):
    print "stop progressbar"
    self.timer.stop()
    self.hide()
Was gethreaded werden soll wärend die ProgressBar läuft wir hier gestartet:

Code: Alles auswählen

class SementationThread(QThread):
  def __init__(self, data,params,parent=None):
    self._data = data
    self._params = params
    QThread.__init__(self,parent)
    
  def run(self):
    self._channel_u,self._channel_v = Module.segmentate(self._data,self._params)
        
  def getResult(self):
    return self._channel_u,self._channel_v

               .
               .
               .

in Module:

def segmentate(data,params):
  threadLock = threading.Lock()
  threads = []
  
  thread1 = SegmentationThread(data,params,'u')
  thread2 = SegmentationThread(data,params,'v')
  
  thread1.start()
  thread2.start()
  
  threads.append(thread1)
  threads.append(thread2)
  
  for t in threads:
      t.join()
  
  result_u = thread1.getResult()
  result_v = thread2.getResult()
  
  return result_u, result_v


In Gui:

Code: Alles auswählen

        self.progressBar.start()
        st = SementationThread(self._data,self._params)
        st.finished.connect(self.stopProgressBar)
        st.start()
        st.wait()

        self._channel_u,self._channel_v = st.getResult()
lunar

@ patrice079: Verzeih mir, doch was hast Du an „minimal“ nicht verstanden?! In dem Quelltext, den Du jetzt gezeigt hast, kann das Problem gar nicht auftreten, da Du "st.wait()" aufrufst, und mithin darauf wartest, dass der Thread beendet wird, so dass der gesamte Thread eigentlich vollkommen überflüssig ist. "segmentate()" funktioniert im Übrigen auch nicht, da Du versuchst, auf einem "QThread"-Objekt ".join()" aufzurufen. Eine Methode dieses Namens gibt es da aber nicht. Zumal die ganze Struktur schon recht merkwürdig ist: Warum startest Du einen Thread, dessen einzige Aufgabe das Starten zweier weiterer Threads ist?!

Also nochmal: Zeige bitte ein vollständiges Beispiel (ohne irgendwelche Auslassungszeichen, Einfügungen, etc.), dass wir ausführen können, welches aber gleichzeitig so minimal ist, dass Du es kurz genug ist um es hier zeigen zu können.
patrice079
User
Beiträge: 13
Registriert: Sonntag 15. April 2012, 13:22

Hallo Lunar,

tut mir leid, aber das ist nicht so einfach, hinter segmentate steckt ziemlich viel code. Das ist eine ganze library die ich jetzt nur gerne in eine Gui packen würde. Die Funktion segmentate nutzt dabei das Threading-Module und ist ursprünglich nicht so geschrieben worden für die Gui. Ich dachte nur ich könnte diese Funktion in der Gui mit einem QThread aufrufen um so aus dem Gui Mainthread rauszukommen damit mir diese nicht einfriert und ich meine Progressbar sehen kann. Ich habe nicht allzu viel Erfahrung bisher mit PyQt4 und vorallem mit Threading und dachte man kann dazu einen einfachen Tip geben was mein Denkfehler ist, denn im Prinzip ist ja alles was ich möchte, eine Funktion aus eine Modul, das nichts mit pyqt zu tun hat, aufzurufen und parallel aber einen Statusbalken zur optischen Rückmeldung wandern lassen.
lunar

@patrice079: Dann ersetze "segmentate" im Beispiel halt durch irgendeinen Dummy. Das Problem liegt nicht in der Bibliothek, sondern in Deiner Oberfläche. Du hast auch keinen Denkfehler, sondern ein spezifisches Problem in Deinem Code. Genau deswegen brauche ich ja ein vollständiges, ausführbares Beispiel, um Dir helfen zu können.
patrice079
User
Beiträge: 13
Registriert: Sonntag 15. April 2012, 13:22

@lunar Danke für Deine Antworten, ich habe das Problem gefunden. Man sollte sich beim threaden Gedanken machen was passieren darf und was nicht bevor ein Thread zu Ende ist. Es wurde wärend des Threads eine Exception geworfen weil ich Ergebnisse schon verwendet habe bevor der Thread zu Ende war. Deswegen hat auch wait() geholfen ;)

Viele Grüße,
Patrice
Antworten