Ausnahmebedingung in TThread Execute?

8

Ich habe gerade festgestellt, dass meine Ausnahmen dem Benutzer in meinen Threads nicht angezeigt werden!

Zuerst habe ich das in meinem Thread benutzt, um die Ausnahme auszulösen, was nicht funktioniert:

%Vor%

Die IDE zeigt mir die Ausnahmen, aber meine App nicht!

Ich habe nach einer Lösung gesucht, das habe ich gefunden:

Delphi Thread-Ausnahmemechanismus

Ссылка

Und beides funktionierte nicht für mich.

Hier ist meine Thread-Einheit:

%Vor%

Wenn Sie weitere Informationen benötigen, lassen Sie es mich wissen.

Nochmal: Die IDE fängt alle Ausnahmen ab, aber mein Programm zeigt sie nicht an.

EDIT: Es war Cosmins Lösung, die am Ende funktionierte - und der Grund, warum es nicht zuerst war, war, dass ich die ErrMsg-Variable nicht hinzugefügt habe, sondern einfach alles, was die Variable enthalten würde, in die Synchronize-Funktion legte würde nicht funktionieren, aber ich habe keine Ahnung warum. Ich habe es realisiert, als ich keine anderen Ideen hatte, und ich habe nur mit den Lösungen herumgespielt.

Wie immer ist der Witz auf mich. = P

    
Jeff 26.03.2011, 14:36
quelle

6 Antworten

9

Hier ist mein sehr, sehr kurzer "Take" zu dem Thema. Es funktioniert nur mit Delphi 2010+ (da diese Version anonyme Methoden eingeführt hat). Im Gegensatz zu den ausgefeilteren Methoden zeigt mine nur die Fehlermeldung, nicht mehr und nicht weniger.

%Vor%     
Cosmin Prund 26.03.2011, 16:41
quelle
13

Etwas sehr Wichtiges, das Sie über die Multi-Thaded-Entwicklung verstehen müssen:

Jeder Thread hat seinen eigenen Aufruf-Stack, fast , als wären es separate Programme. Dies beinhaltet den Haupt-Thread Ihres Programms.

Threads können nur auf bestimmte Arten miteinander interagieren:

  • Sie können gemeinsame Daten oder Objekte bearbeiten. Dies kann zu Nebenläufigkeitsproblemen führen und daher müssen Sie in der Lage sein, ihnen zu helfen, Daten schön zu teilen. Das bringt uns zum nächsten Punkt.
  • Sie können sich gegenseitig "signalisieren", indem sie eine Vielzahl von Betriebssystem-Support-Routinen verwenden. Dazu gehören Dinge wie:
    • Mutexe
    • Kritische Abschnitte
    • Ereignisse
  • Und schließlich können Sie Nachrichten an andere Threads senden. Vorausgesetzt, der Thread wurde in gewisser Weise als Nachrichtenempfänger geschrieben.

NB : Beachten Sie, dass Threads streng genommen andere Threads nicht direkt aufrufen können. Wenn zum Beispiel Thread A versucht, Thread B direkt aufzurufen, wäre das ein Schritt auf dem Call-Stack von Thread A!

Dies bringt uns zum Thema der Frage: "Ausnahmen werden in meinen Threads nicht ausgelöst"

Der Grund dafür ist, dass alles eine Ausnahme ist:

  • Notieren Sie den Fehler
  • Und wickeln Sie den Call-Stack ab . & lt; - Hinweis: Ihre TThread-Instanz kann den Aufruf-Stack des Haupt-Threads nicht abwickeln und die Ausführung der Haupt-Threads nicht willkürlich unterbrechen.

So wird TThread nicht automatisch Ausnahmen für Ihre Hauptanwendung melden.

Sie müssen die explizite Entscheidung treffen, wie Sie Fehler in Threads behandeln und entsprechend implementieren möchten.

Lösung

  • Der erste Schritt ist der gleiche wie in einer Anwendung mit einem einzigen Thread. Sie müssen entscheiden, was der Fehler bedeutet und wie der Thread reagieren soll.
    • Sollte der Thread die Verarbeitung fortsetzen?
    • Sollte der Thread abbrechen?
    • Soll der Fehler protokolliert / gemeldet werden?
    • Braucht der Fehler eine Benutzerentscheidung? & lt; - Dies ist mit Abstand am schwierigsten zu implementieren, daher werden wir es vorerst überspringen.
  • Sobald dies entschieden wurde, implementieren Sie den entsprechenden Exception-Handler.
  • TIP: Make sure the exception doesn't escape the thread. The OS won't like you if it does.
  • Wenn Sie das Hauptprogramm (Thread) benötigen, um den Fehler dem Benutzer zu melden, haben Sie einige Optionen.
    • Wenn der Thread geschrieben wurde, um ein Ergebnisobjekt zurückzugeben, dann ist es einfach: Nehmen Sie eine Änderung vor, damit der Fehler in diesem Objekt zurückgegeben werden kann, wenn etwas schief gelaufen ist.
    • Senden Sie eine Nachricht an den Hauptthread, um den Fehler zu melden. Beachten Sie, dass der Hauptthread bereits eine Nachrichtenschleife implementiert, sodass Ihre Anwendung den Fehler meldet, sobald sie diese Nachricht verarbeitet.

EDIT: Codebeispiel für die angegebene Anforderung.

Wenn Sie lediglich den Benutzer benachrichtigen möchten, Cosmind Prunds Antwort  sollte für Delphi 2010 perfekt funktionieren. Ältere Versionen von Delphi brauchen etwas mehr Arbeit. Das Folgende ist konzeptionell ähnlich wie Jeffs eigene Antwort , aber ohne die Fehler :

%Vor%

Einige wichtige Korrekturen zu Jeffs eigener Antwort, einschließlich der Implementierung in seiner Frage:

Der Aufruf von Terminate ist nur relevant, wenn Ihr Thread in einer while not Terminated do ... -Schleife implementiert ist. Sehen Sie sich an, was die Methode Terminate tatsächlich macht.

Der Aufruf von Exit ist eine unnötige Verschwendung, aber Sie haben das wahrscheinlich wegen Ihres nächsten Fehlers getan.

In Ihrer Frage wickeln Sie jeden Schritt in seinem eigenen try...except ab, um die Ausnahme zu behandeln. Das ist ein absolutes no-no ! Indem Sie dies tun, geben Sie vor, dass, obwohl eine Ausnahme aufgetreten ist, alles in Ordnung ist. Ihr Thread versucht den nächsten Schritt, aber es ist tatsächlich garantiert fehlgeschlagen! Dies ist nicht die Art, Ausnahmen zu behandeln!

    
Craig Young 26.03.2011 17:27
quelle
6

Threads verbreiten Ausnahmen nicht automatisch in andere Threads. Du musst also selbst damit umgehen.

Rafael hat einen Ansatz skizziert, aber es gibt Alternativen. Die Lösung, auf die Rafael hinweist, behandelt die Ausnahme synchron, indem sie in den Hauptthread eingeordnet wird.

In einer meiner eigenen Threading-Anwendungen, einem Thread-Pool, fangen und übernehmen die Threads den Besitz der Ausnahmen. Dies ermöglicht es dem steuernden Thread, sie so zu behandeln, wie es Ihnen gefällt.

Der Code sieht so aus.

%Vor%

Wenn der steuernde Thread die Ausnahme auswählt, kann er dies folgendermaßen tun:

%Vor%

Manchmal haben Sie möglicherweise Code, der Synchronize nicht aufrufen kann, z. einige DLLs und dieser Ansatz ist nützlich.

Beachten Sie, dass wenn Sie die Ausnahme, die erfasst wurde, nicht auslösen, dann muss es zerstört werden, andernfalls haben Sie einen Speicherverlust.

    
David Heffernan 26.03.2011 15:00
quelle
3

Nun,

Es wird schwer ohne Ihren Quellcode, aber ich habe das getestet:

So behandeln Sie Ausnahmen in TThread-Objekten

Und es funktioniert gut. Vielleicht sollten Sie es sich ansehen.

BEARBEITEN:

Sie folgen nicht den Anweisungen, auf die Sie uns hinweisen. Überprüfen Sie meinen Link und Sie werden sehen, wie das geht.

EDIT 2:

Probieren Sie das aus und sagen Sie mir, ob es funktioniert hat:

%Vor%

EDIT 3:

Sie haben gesagt, dass Sie EIdHTTPProtocolException nicht abfangen können. Aber es funktioniert für mich. Probieren Sie dieses Beispiel aus und sehen Sie es sich selbst an:

%Vor%     
Rafael Colucci 26.03.2011 14:49
quelle
2

Ich habe zuvor SendMessge für die Inter-Thread-Kommunikation mit TWMCopyData verwendet, daher sollte das Folgende funktionieren:

%Vor%

Ich habe es nur benutzt, um einfache Datentypen oder Strings zu senden, aber ich bin mir sicher, dass es angepasst werden könnte, um mehr Informationen nach Bedarf zu senden.

Sie müssen Self.Handle zum Konstruktor hinzufügen, indem Sie den Thread erstellt und die Nachricht in der Form bearbeitet haben, in der sie erstellt wurde

%Vor%     
James Barrass 26.03.2011 17:20
quelle
1

Seltsam, dass alle diese Frage beantwortet haben, aber das offensichtliche Problem nicht erkannt haben: Da in einem Hintergrund-Thread generierte Ausnahmen asynchron sind und jederzeit auftreten können, würde das Anzeigen von Ausnahmen aus einem Hintergrundthread einen Dialog öffnen Box zu zufälligen Zeiten an den Benutzer, möglicherweise eine Ausnahme, die nichts mit dem zu tun hat, was der Benutzer im Moment tut. Ich bezweifle, dass dies möglicherweise die Benutzererfahrung verbessern könnte.

    
Misha 26.03.2011 23:04
quelle