Thread-Problem

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Steffo
User
Beiträge: 45
Registriert: Sonntag 24. Mai 2009, 19:38

Hallo,
ich habe ein Programm mit verschiedenen Threads, die sekündlich einen bestimmten Status abfragen und ihn anschließend der GUI (Tkinter) mitteilen.
Das Problem ist nur, dass wenn ich das Programm beende, anscheinend Tkinter-Objekte vorher zerstört werden, die Threads noch im Hintergrund laufen und auf die GUI zugreifen wollen und es anschließend zu einer Exception führt (nicht immer, aber eben manchmal).
Hier die Fehlermeldung:

Code: Alles auswählen

Unhandled exception in thread started by <bound method Controller.watchPortStatus of <src.controller.Controller.Controller object at 0x00C1AB30>>
Traceback (most recent call last):
  File "C:\Documents and Settings\stdi3650\My Documents\Aptana Studio 3 Workspace\COM-CommunicatorV4\src\controller\Controller.py", line 102, in watchPortStatus
    portListButtons[i]['background'] = 'green'
  File "C:\Python25\lib\lib-tk\Tkinter.py", line 1204, in __setitem__
    self.configure({key: value})
  File "C:\Python25\lib\lib-tk\Tkinter.py", line 1197, in configure
    return self._configure('configure', cnf, kw)
  File "C:\Python25\lib\lib-tk\Tkinter.py", line 1188, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: invalid command name ".12709320.12709680.12718848"
Hier der Code:

Code: Alles auswählen

def watchPortStatus(self, portListButtons): # Funktion, die von einem separaten Thread ausgeführt wird.
    while self.com.connectionIsOpen():
        with self._port_button_lock:
            portStatus = self.com.getPortStatusFromDevice()
            
            for i in range(len(portListButtons)):
                currentPortMask = (1 << i)
                
                if (currentPortMask & portStatus == currentPortMask):
                    portListButtons[i]['background'] = 'green'
                else:
                    portListButtons[i]['background'] = 'red'
        time.sleep(1)
Weiß jemand, wie ich das Problem umgehen/beheben kann?
Danke im Voraus!

L. G.
Steffo
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo Steffo,

beheben: dafür sorgen, dass die Threads vor der GUI beendet werden.
Also self.com-Connection schließen und mit thread.wait() warten bis der Thread sich beendet hat.

umgehen: per try-except den Fehler abfangen.

Grüße
Sirius

PS: für die for-Schleife enumerate benutzen.

Code: Alles auswählen

def watchPortStatus(self, portListButtons): # Funktion, die von einem separaten Thread ausgeführt wird.
    while self.com.connectionIsOpen():
        with self._port_button_lock:
            portStatus = self.com.getPortStatusFromDevice()
           
            for i, btn in enumerate(portListButtons):
                currentPortMask = (1 << i)
                try:
                  btn['background'] = 'green' if currentPortMask & portStatus != 0 else 'red'
                except:
                  pass
        time.sleep(1)
Steffo
User
Beiträge: 45
Registriert: Sonntag 24. Mai 2009, 19:38

Hi Sirius,
danke für deine Antwort.
Ich schätze du meinst join() und nicht wait(). ;)
Ich habe dummerweise das Problem, dass ich das thread- und nicht das threading-Modul verwende, welches wiederum Klassen mit run()-Methoden braucht...
Muss ich nun tatsächlich Klassen um die Funktionen drum herum bauen?!

L. G.
Steffo
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Steffo hat geschrieben:Ich habe dummerweise das Problem, dass ich das thread- und nicht das threading-Modul verwende, welches wiederum Klassen mit run()-Methoden braucht...
Muss ich nun tatsächlich Klassen um die Funktionen drum herum bauen?!
Nein, musst du nicht. Erstens solltest du das High-Level-Modul threading verwenden, nicht das Low-Level-Modul thread. Zweitens kannst du threading.Thread Objekte einfach so erzeugen, indem du eine Funktion übergibst, die dann in dem Thread ausgeführt wird:

Code: Alles auswählen

import threading

def foo(some_arg, some_other_arg):
    while some_condition:
        ...

my_thread = threading.Thread(target=foo, args=(7, 'hallo'))
my_thread.start()
...
my_thread.join()
In specifications, Murphy's Law supersedes Ohm's.
Steffo
User
Beiträge: 45
Registriert: Sonntag 24. Mai 2009, 19:38

OK, danke!!! :)
Antworten