Unhandled exception unter Windows

Plattformunabhängige GUIs mit wxWidgets.
Antworten
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

Moin moin,

ich bekomme in letzter Zeit in regelmäßigen Abständen eine Fehlermeldung, die ich nicht zurückverfolgen kann. Das ganze passiert unter Windows, unter Linux hab ich noch nichts vergleichbares feststellen können und endet mit einer Fehler-Dialogbox die wie folgt aussieht:

___________________________________________
Unhandled exception
------------------------------------------------------------
An unhandled exception occurred. Press "Abort" to terminate the program, "Retry" to exit the program normally and "Ignore" to try to continue.

Abbrechen Wiederholen Ingnorieren
------------------------------------------------------------

Hier noch ein paar Module, die ich verwende:

Code: Alles auswählen

import wx
from wx.lib.embeddedimage import PyEmbeddedImage 
from wx.lib.wordwrap import wordwrap
import wx.lib.sized_controls as sc
import os, sys, time
from threading import Thread, Event, RLock
import ConfigParser
import shutil
import re
import webbrowser as wb
import codecs
from base64 import b64decode
from uuid import uuid1
from StringIO import StringIO
Ich nutze u.a. die Widgets wx.html.HtmlWindow und wx.TreeCtrl neben denn "normalen" Frame-Element (ToolBar etc.).

Für Ratschläge oder Ideen wäre ich sehr dankbar.
BlackJack

@IoI: Also wenn ich raten müsste, dann greifst Du aus Threads auf die GUI zu, aus denen Du das nicht dürftest!?
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

Also ich habe einen Thread, der auf die GUI massive zugreift, um zum Beispiel den Inhalt in meinem HtmlWindow zu ändern.

EDIT: Das ist nötig, weil es Abläufe gibt, die asynchron zur GUI ab laufen.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

IoI hat geschrieben:Also ich habe einen Thread, der auf die GUI massive zugreift, um zum Beispiel den Inhalt in meinem HtmlWindow zu ändern.

EDIT: Das ist nötig, weil es Abläufe gibt, die asynchron zur GUI ab laufen.
Richtiger wäre: Der asynchrone Thread kommt zu einem bestimmten Ergebnis und sendet ein Signal an den Thread, in dem die GUI läuft. Dieser holt sich dann die Werte vom asynchronen Thread und aktualisiert die Oberfläche. Ich kenne kein GUI-Toolkit, daß es auf Dauer tolerieren würde, wenn man aus einem anderen Thread heraus direkt auf die GUI zugreifen würde. Und es ist auch alles andere als ein sauberes Design.
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

Also pollt die GUI quasi werte aus dem Thread? Wo realisiert man das den am besten? Im Idle Event?

Hab gerade nochmal nach geschaut, neben dem Befüllen des HtmlWindow enable bzw. disable ich noch Menü-Eintrage und Buttons.

EDIT: Achso, aus der GUI heraus löse ich hin und wieder noch ein Event im Thread aus.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Kommunikation zwischen Threads/Prozessen ist ein weites, nicht unkompliziertes Feld mit vielen Möglichkeiten. Eine kurze Google-Recherche wird dir eine Menge Material liefern. Die verwendete Programmiersprache ist dabei praktisch egal, da die Probleme und Konzepte eigentlich überall die gleichen sind.

wxPython verfügt über Timer und Threading-Unterstützung. Habe ich mich noch nicht im Detail mit auseinandergesetzt, wäre aber der zu gehende Weg.
Schau mal in der wx-Demo, dann bei wxpython.org (wiki und doku) und dann bei Google. Hier im Forum dürftest du auch ein paar Ansätze finden.
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

Okay, danke für die Tipps.

Ich versuche es jetzt mit folgendem:

zunächst erstelle ich ein neues Event

Code: Alles auswählen

import  wx.lib.newevent
(ItemUpdate, EVT_ITEM_UPDATE) = wx.lib.newevent.NewEvent()
Binde das ganze an eine Funktion in meinem wx.Frame

Code: Alles auswählen

self.Bind(EVT_ITEM_UPDATE, self.OnItemUpdate)
Dann löse ich es in meinen asynchronen Thread aus.

Code: Alles auswählen

evt = ItemUpdate(uebergabe=daten)
wx.PostEvent(self.win, evt)
Ich werde berichten, falls der Fehler trotzdem noch auftritt.
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Wenn du auch nur irgendetwas aus dem Modul wx in deinem asynchronen Thread verwendest, machst du etwas falsch.



Deine GUI hat ihren eigenen Rhythmus, entscheidet selbst, wann sie welche Ereignisse wie behandelt.

Um das Problem mal mit einem etwas extremen Beispiel zu illustrieren:
Angenommen du hast einen Button, an den du einen Event-Handler gehängt hast. Du klickst drauf, und der Handler beginnt seine Arbeit. Mittendrin ist die dem Prozeß zugeteilte Zeit vorüber, der GUI-Thread wird unterbrochen und der asynchrone Thread kommt an die Reihe. Angenommen in diesem asynchronen Thread löscht du den Button. Du erzeugst damit einen instabilen Zustand. Wenn der GUI-Thread wieder an die Reihe kommt, fährt er mit der Abarbeitung des Handlers fort - unter der Annahme, der Button würde noch existieren. Am Ende des Handlers wird die GUI den Button neu zeichnen wollen - der aber gar nicht mehr vorhanden ist -> Ausnahme. Ähnliches, aber viel subtiler passiert, wenn du irgendwelche Werte oder Einstellungen änderst.

Du darfst die GUI bzw. deren Thread von außen nicht beeinflußen, auch nicht durch Events. Stattdessen muß der GUI-Thread zu bestimmten Zeitpunkten nachsehen, ob der asynchrone Thread Änderungsbedarf signalisiert hat.

Der asynchrone Thread weiß idealerweise gar nichts über die GUI. Er macht seine Arbeit, und überläßt die Interpretation seines Zustandes den anderen.
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

Also, im Thread lese ich jetzt nur noch Werte aus und übergebe dann meine gewünschten Änderungen an die GUI über das Event z.B. der Button mit der ID XYZ soll deaktiviert werden. In dem Event-Handler wird dies dann gemacht. Dürfte kein Problem geben, weil dort die einzige stelle ist in der Buttons und Menüpunkte aktiviert/deaktiviert werden.

Die zweite Aufgabe ist da schon kritischer. Mit ihr soll übergebenen werden, dass ein neuer Inhalt in das HtmlWindow geladen wird. Um Konflikte mit der GUI zu vermeiden (die das auch kann) habe ich ein RLock erstellt, welches benötigt wird, um das HtmlWindow zu verändern. Ist der RLock bereits vergeben setze ich in der GUI einen Boolean, der der Idle-Task signalisiert bei nächster Gelegenheit es erneut zu versuchen (und das ja den im GUI-Thread kontext).

Ich hoffe das ich mich damit ausreichend gegen Kollisionen abgesichert habe, weitere Ideen würden mich aber durchaus interessieren.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Pekh hat geschrieben:Wenn du auch nur irgendetwas aus dem Modul wx in deinem asynchronen Thread verwendest, machst du etwas falsch.
Das stimmt so nicht. wx.CallAfter und wx.PostEvent sind durchaus Vorgehensweisen, die in wxPython in Action empfohlen werden.
MfG
HWK
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

HWK hat geschrieben:
Pekh hat geschrieben:Wenn du auch nur irgendetwas aus dem Modul wx in deinem asynchronen Thread verwendest, machst du etwas falsch.
Das stimmt so nicht. wx.CallAfter und wx.PostEvent sind durchaus Vorgehensweisen, die in wxPython in Action empfohlen werden.
MfG
HWK
Tatsächlich. :shock:
Ich finde das allerdings im Hinblick auf die oft beschworene Trennung von Oberfläche und Programmlogik nicht gerade sauber. Aber gut, muß jeder halt selbst sehen, wie er damit umgeht.
IoI
User
Beiträge: 68
Registriert: Dienstag 1. Dezember 2009, 11:39

Pekh hat geschrieben:
HWK hat geschrieben:
Pekh hat geschrieben:Wenn du auch nur irgendetwas aus dem Modul wx in deinem asynchronen Thread verwendest, machst du etwas falsch.
Das stimmt so nicht. wx.CallAfter und wx.PostEvent sind durchaus Vorgehensweisen, die in wxPython in Action empfohlen werden.
MfG
HWK
Tatsächlich. :shock:
Ich finde das allerdings im Hinblick auf die oft beschworene Trennung von Oberfläche und Programmlogik nicht gerade sauber. Aber gut, muß jeder halt selbst sehen, wie er damit umgeht.
was wäre denn deine Lösungsansatz für ein solches Verhalten? Vielleicht als kurzer Codeschnipsel. Ich lerne immer gerne noch was dazu ^^
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

IoI hat geschrieben: was wäre denn deine Lösungsansatz für ein solches Verhalten? Vielleicht als kurzer Codeschnipsel. Ich lerne immer gerne noch was dazu ^^
Das hängt ein bisschen davon ab, was der asynchrone Thread im Detail tut, und was in der GUI passieren soll. Angenommen der Thread soll irgendwelche längeren Berechnungen durchführen und in der GUI soll eine Statusanzeige aktualisiert werden. Dann würde ich dem Thread bei Erstellung ein Objekt übergeben, in das er munter seine Statusmeldungen schreiben kann (z.B. einen Prozentwert). Die GUI, die diese gemeinsame Ressource ebenfalls kennt, kann diesen Statuswert dann in bestimmten Abständen auslesen und darstellen. Auf Seite von wx würde ich hierfür einen wxTimer verwenden. Da die GUI in diesem Fall ausschließlich lesend auf die gemeinsame Ressource zugreift, müßte man diese vermutlich nicht einmal besonders absichern. Anders würde es aussehen, wenn beide Seiten schreibend zugreifen könnten und / oder der Lesezugriff nicht atomar ist. Dann müßte man z.B. mit Semaphoren sicherstellen, daß keine Inkonsistenzen auftreten können.

Einen Codeschnippsel muß ich dir jetzt erst einmal schuldig bleiben, bin ohnehin schon am prokrastinieren (was für ein Wort!) :)
Antworten