Fang eine Ausnahme, die in einem anderen Thread ausgelöst wird
109
Eine meiner Methoden ( Method1) erzeugt einen neuen Thread. Dieser Thread führt eine Methode ( Method2) aus und während der Ausführung wird eine Ausnahme ausgelöst. Ich muss diese Ausnahmeinformationen über die aufrufende Methode ( Method1) erhalten
Gibt es eine Möglichkeit, diese Ausnahme zu erkennen Method1, die eingeworfen wird Method2?
In .NET 4 und höher können Sie die Task<T>Klasse verwenden, anstatt einen neuen Thread zu erstellen. Anschließend können Sie mithilfe der .ExceptionsEigenschaft für Ihr Aufgabenobjekt Ausnahmen abrufen. Es gibt zwei Möglichkeiten, dies zu tun:
In einer separaten Methode: // Sie verarbeiten Ausnahmen im Thread einer Aufgabe
Entschuldigung, aber ich habe vergessen zu erwähnen, dass ich .NET 3.5 verwende. Nach meinem Verständnis ist Aufgabe 4.0 Sache?
Silverlight Student
2
@SilverlightStudent Ok, ich habe gerade meine Antwort aktualisiert, um Ihre Anforderungen zu erfüllen.
Oxilumin
@ Oxilumin: Danke und sehr geschätzt. Noch eine Folgefrage. Wenn Ihre Test () -Methode auch einige Argumente akzeptiert, wie können Sie dann die SafeExecute-Methode für diese Argumente ändern?
Silverlight Student
2
@ SilverlightStudent In diesem Fall übergebe ich stattdessen ein Lambda Test. Like() => Test(myParameter1, myParameter2)
Oxilumin
2
@ SilverlightStudent: Aktualisiert.
Oxilumin
9
Sie können die Ausnahme in Methode1 nicht abfangen. Sie können die Ausnahme jedoch in Methode 2 abfangen und in einer Variablen aufzeichnen, die der ursprüngliche Ausführungsthread dann lesen und bearbeiten kann.
Vielen Dank für Ihre Antwort. Wenn also Methode1 Teil von Klasse1 ist und ich in dieser Klasse eine Variable vom Typ Exception habe. Immer wenn Methode2 eine Ausnahme auslöst, wird diese Ausnahmevariable auch in Klasse1 festgelegt. Klingt es nach einem fairen Design? Gibt es Best-Practice-Methoden für den Umgang mit diesem Szenario?
Silverlight Student
Richtig, Sie speichern nur die Ausnahme und greifen später darauf zu. Es ist nicht ungewöhnlich, dass in Zukunft ausgeführte Methoden (insbesondere Rückrufe, wenn Methode2 abgeschlossen ist) diese Ausnahme erneut auslösen, als hätten sie sie selbst verursacht. Dies hängt jedoch wirklich davon ab, was Sie möchten.
Ermau
0
Die einfachste Methode zum Teilen von Daten zwischen verschiedenen Threads ist shared datadie folgende (einige sind Pseudocode):
classMyThread{publicstringSharedData;publicvoidWorker(){...lengthy action, infinite loop, etc...SharedData="whatever";...lengthy action...return;}}classProgram{staticvoidMain(){MyThread m =newMyThread();ThreadWorkerThread=newThread(m.Worker);WorkerThread.Start();
loop//or e.g. a Timer thread{
f(m.SharedData);}return;}}
Sie können über diese Methode in dieser schönen Einführung zum Thema Multithreading lesen. Ich habe es jedoch vorgezogen, darüber in der O'Reilly book C# 3.0 in a nutshellvon den Brüdern Albahari (2007) zu lesen , die ebenso wie die neuere Version des Buches auch in Google Books frei zugänglich ist. weil es auch Thread-Pooling, Vordergrund- und Hintergrund-Threads usw. usw. mit nettem und einfachem Beispielcode abdeckt. (Haftungsausschluss: Ich besitze eine abgenutzte Ausgabe dieses Buches)
Wenn Sie eine WinForms-Anwendung erstellen, ist die Verwendung freigegebener Daten besonders praktisch, da die WinForm-Steuerelemente nicht threadsicher sind. Wenn Sie einen Rückruf verwenden, um Daten vom Worker-Thread an ein WinForm-Steuerelement zurückzugeben, benötigt der Haupt-UI-Thread hässlichen Code Invoke(), um dieses Steuerelement threadsicher zu machen. Wenn Sie stattdessen gemeinsam genutzte Daten und den Single-Thread verwenden System.Windows.Forms.Timer, können Sie mit einer kurzen Zeit Intervalvon beispielsweise 0,2 Sekunden problemlos Informationen vom Worker-Thread an das Steuerelement senden, ohne Invoke.
Ich hatte ein besonderes Problem darin, dass ich Elemente mit Steuerelementen aus einer Integrationstestsuite verwenden wollte, also einen STA-Thread erstellen musste. Der Code, mit dem ich am Ende endete, lautet wie folgt, falls andere das gleiche Problem haben.
publicBoolean?Dance(String name){// Already on an STA thread, so just go for itif(Thread.CurrentThread.GetApartmentState()==ApartmentState.STA)returnDanceSTA(name);// Local variable to hold the caught exception until the caller can rethrowException lException =null;Boolean? lResult =null;// A gate to hold the calling thread until the called thread is donevar lGate =newManualResetEvent(false);var lThreadStart =newThreadStart(()=>{try{
lResult =DanceSTA(name);}catch(Exception ex){
lException = ex;}
lGate.Set();});var lThread =newThread(lThreadStart);
lThread.SetApartmentState(ApartmentState.STA);
lThread.Start();
lGate.WaitOne();if(lException !=null)throw lException;return lResult;}publicBoolean?DanceSTA(String name){...}
Dies ist eine direkte Einfügung des Codes wie er ist. Für andere Zwecke würde ich empfehlen, eine Aktion oder Funktion als Parameter anzugeben und diese im Thread aufzurufen, anstatt die aufgerufene Methode fest zu codieren.
Test
. Like() => Test(myParameter1, myParameter2)
Sie können die Ausnahme in Methode1 nicht abfangen. Sie können die Ausnahme jedoch in Methode 2 abfangen und in einer Variablen aufzeichnen, die der ursprüngliche Ausführungsthread dann lesen und bearbeiten kann.
quelle
Die einfachste Methode zum Teilen von Daten zwischen verschiedenen Threads ist
shared data
die folgende (einige sind Pseudocode):Sie können über diese Methode in dieser schönen Einführung zum Thema Multithreading lesen. Ich habe es jedoch vorgezogen, darüber in der
O'Reilly book C# 3.0 in a nutshell
von den Brüdern Albahari (2007) zu lesen , die ebenso wie die neuere Version des Buches auch in Google Books frei zugänglich ist. weil es auch Thread-Pooling, Vordergrund- und Hintergrund-Threads usw. usw. mit nettem und einfachem Beispielcode abdeckt. (Haftungsausschluss: Ich besitze eine abgenutzte Ausgabe dieses Buches)Wenn Sie eine WinForms-Anwendung erstellen, ist die Verwendung freigegebener Daten besonders praktisch, da die WinForm-Steuerelemente nicht threadsicher sind. Wenn Sie einen Rückruf verwenden, um Daten vom Worker-Thread an ein WinForm-Steuerelement zurückzugeben, benötigt der Haupt-UI-Thread hässlichen Code
Invoke()
, um dieses Steuerelement threadsicher zu machen. Wenn Sie stattdessen gemeinsam genutzte Daten und den Single-Thread verwendenSystem.Windows.Forms.Timer
, können Sie mit einer kurzen ZeitInterval
von beispielsweise 0,2 Sekunden problemlos Informationen vom Worker-Thread an das Steuerelement senden, ohneInvoke
.quelle
Ich hatte ein besonderes Problem darin, dass ich Elemente mit Steuerelementen aus einer Integrationstestsuite verwenden wollte, also einen STA-Thread erstellen musste. Der Code, mit dem ich am Ende endete, lautet wie folgt, falls andere das gleiche Problem haben.
Dies ist eine direkte Einfügung des Codes wie er ist. Für andere Zwecke würde ich empfehlen, eine Aktion oder Funktion als Parameter anzugeben und diese im Thread aufzurufen, anstatt die aufgerufene Methode fest zu codieren.
quelle