Einsatz von mehreren Threads

Plattformunabhängige GUIs mit wxWidgets.
Antworten
george
User
Beiträge: 109
Registriert: Mittwoch 11. Januar 2006, 20:28
Wohnort: Berlin

Hallo,

ich habe eine Applikation, in der Messwerte von einer Hardwareplatine als Diagramm und als Messwert dargestellt werden.
Die Messwerte werden alle 50mSec timer-getriggert von der Platine abgeholt.

Zur Visualisierung habe ich jetzt zwei Threads gestartet.
Einem zum Aktualiseren des Diagramms und den zweiten zum aktualisieren der Messwerte in Form von wxStaticText.

Code: Alles auswählen

thread.start_new_thread(self.RedrawGraph, ())
thread.start_new_thread(self.RedrawValues, ())


def RedrawValues(self):
   while (self.__btnState == BtnState.BTN_STATE_MONITOR):
      if (self.__CaptureCounter >= 5):
         self.staticTextDiffVal.SetLabel(str(self.__curDiff))
         self.staticTextKalVal.SetLabel(str(self.__curGCF))
         
        
    
def RedrawGraph(self):
   while (self.__btnState == BtnState.BTN_STATE_MONITOR):
      if (self.__CaptureCounter >= 5):
         self.__PlotCurve()
         
Mein Problem ist, wenn ich beide Threads zum Aktualisieren der GUI starte, wird nur die Aktualisierung der GUI durch den zuletzt gestarteten Thread durchgeführt. Dies bedeutet, nur die Funktion "RedrawValues" wird ausgeführt. Das Diagramm wird im diesem Fall dann nicht mehr aktualisiert.
Probehalber habe ich nur den Thread zum Aktualisieren des Diagramms("RedrawGraph") gestartet. In diesem Fall funktioniert die Aktualisierung des Diagramms und man erhält eine laufende Kennlinie für die Messwerte.

Hat jemand eine Idee, warum bei zwei Threads nur der eine ausgeführt wird?
Eine Zusammenfassung der GUI-Aktualisierung in einem Thread(Diagramm und Messwerte) möchte ich vermeiden.

Danke für eure Hilfe

greets george
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

george hat geschrieben:Hat jemand eine Idee, warum bei zwei Threads nur der eine ausgeführt wird?
Hi George!

Ich weiß nicht ob es daran liegt, aber du greifst von den Threads, aus auf Funktionen des Hauptthreads zurück. Das funktioniert nicht so richtig. Du musst mit ``wx.CallAfter()`` arbeiten, wenn du die Threadgrenzen überschreitest.

Weiters lasst du den Threads keine Verschnaufpause. Beide Threads laufen in einer Endlosschleife -- so schnell es der Prozessor erlaubt. Ich würde da, wenn es die Betriebssystemumgebung erlaubt, je ein ``time.sleep(0.001)`` oder etwas ähnliches einbauen, damit sich die Threads nich gegenseitig die kompletten Ressourcen wegschnappen.

Code: Alles auswählen

def RedrawValues(self):
   while (self.__btnState == BtnState.BTN_STATE_MONITOR):
      # Hier sollte man den Thread kurz warten lassen, damit sich der
      # Prozessor wieder erholen kann.
      if (self.__CaptureCounter >= 5):
         # self.staticTextDiffVal.SetLabel(str(self.__curDiff))
         wx.CallAfter(self.staticTextDiffVal.SetLabel, str(self.__curDiff)) # Aufruf über Thread-Grenze hinweg.
         # self.staticTextKalVal.SetLabel(str(self.__curGCF))
         wx.CallAfter(self.staticTextKalVal.SetLabel, str(str(self.__curGCF))) # Aufruf über Thread-Grenze hinweg.

def RedrawGraph(self):
   while (self.__btnState == BtnState.BTN_STATE_MONITOR):
      # Hier sollte man den Thread kurz warten lassen, damit sich der
      # Prozessor wieder erholen kann.
      if (self.__CaptureCounter >= 5):
         # self.__PlotCurve()
         wx.CallAfter(self.__PlotCurve) # Aufruf über Thread-Grenze hinweg.

thread.start_new_thread(self.RedrawGraph, ())
thread.start_new_thread(self.RedrawValues, ())
(Vorsicht: ungetesteter Pseudocode)

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
george
User
Beiträge: 109
Registriert: Mittwoch 11. Januar 2006, 20:28
Wohnort: Berlin

Hallo gerold,

ich danke dir für deine Antwort.
Ich habe jetzt den Workflow nochmal umgestaltet. Für die Messwerteaufnahme habe ich eine separate Thread-Klasse erzeugt. In der run-loop trigger ich jetzt alle 50mSec die Messwertaufnahme und erzeuge anschließend ein eigenes Event. Dieses wird dann im MainThread(GUI) registriert. Dem Eventobjekt gebe ich dann die Messdaten mit. Funktioniert sauber.
Meiner Meinung nach ist dies die saberste Lösung.

greets george
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

In wxPython in Action wird auf Seite 539f. daraufhingewiesen, dass GUI-Operationen in wxPython nur im Thread mit der MainLoop, also meistens im Main-Thread erfolgen sollten, da es sonst zu Abstürzen kommen kann. Deshalb ist Deine Lösung korrekt, die in einem Extra-Thread gewonnenen Daten an den Haupt-Thread zur Ausgabe zu übergeben. Ich habe in einem ähnlichen Problem die Daten über Variablen übergeben, die durch einen Timer regelmäßig abgefragt werden. Deine Lösung mit einem eigenen Event klingt aber besser.
MfG
HWK
Antworten