8 Stimmen

Wie kann ich eine ThreadAbortException in einem finally-Block erkennen? (.NET)

Ich habe einige kritische Logik in einem finally-Block (mit einem leeren try-Block), weil ich garantieren möchte, dass der Code ausgeführt wird, auch wenn der Thread abgebrochen wird. Allerdings möchte ich auch die ThreadAbortException erkennen. Ich habe festgestellt, dass die ThreadAbortException nicht abgefangen wird, wenn ich meinen kritischen try/finally-Block in ein try/catch einpacke. Gibt es eine Möglichkeit, sie zu erkennen?

try {
    try { }
    finally {
        // critical logic
    }
} catch(Exception ex) {
    // ThreadAbortException is not caught here, but exceptions thrown
    // from within the critical logic are
}

8voto

Jordão Punkte 53117

Dies ist ein merkwürdiges Problem.

Der von Ihnen gepostete Code sollte arbeiten. Es scheint, dass eine Art Optimierung im Gange ist, die beschließt, Ihren Catch-Handler nicht aufzurufen.

Ich wollte damit die Ausnahme aufdecken:

bool threadAborted = true;
try {
  try { }
  finally { /* critical code */ }
  threadAborted = false;
}
finally {
  Console.WriteLine("Thread aborted? {0}", threadAborted);
}
Console.WriteLine("Done");

(Mein eigentlicher Code schlief einfach in diesem kritischen Codeabschnitt, so dass ich sicher sein konnte, dass er danach endlich abbricht).

Es wurde gedruckt:

Thema abgebrochen? Falsch

Hmmm, in der Tat seltsam!

Also habe ich mir überlegt, dort noch etwas mehr Arbeit zu leisten, um irgendwelche "intelligenten" Optimierungen auszutricksen:

bool threadAborted = true;
try {
  try { }
  finally { /* critical code */ }
  threadAborted = AmIEvil();
}
finally {
  Console.WriteLine("Thread aborted? {0}", threadAborted);
}
Console.WriteLine("Done");

Wo AmIEvil ist gerecht:

[MethodImpl(MethodImplOptions.NoInlining)]
static bool AmIEvil() {
  return false;
}

Schließlich wurde er gedruckt:

Thema abgebrochen? Wahr

Und da haben Sie es. Verwenden Sie dies in Ihrem Code:

try {
  try { }
  finally { /* critical code */ }
  NoOp();
}
catch (Exception ex) {
  // ThreadAbortException is caught here now!
}

Wo NoOp ist gerecht:

[MethodImpl(MethodImplOptions.NoInlining)]
static void NoOp() { }

0 Stimmen

Das Finale wird nicht übersprungen. Die ThreadAbortException wartete darauf, geworfen zu werden, bis nach die catch weil die try in einer CER (Constrained Execution Region) lag. Der Methodenaufruf macht es so, dass es keine CER sein kann.

3voto

JaredPar Punkte 699699

Sie können Code in der catch-Anweisung für eine ThreadAbortException problemlos ausführen. Das Problem ist, dass die Ausnahme erneut ausgelöst wird, sobald die Ausführung den Catch-Block verlässt.

Wenn Sie die Fortsetzung der Ausnahme tatsächlich verhindern wollen, können Sie Thread.ResetAbort() aufrufen. Dies erfordert jedoch volles Vertrauen, und wenn Sie kein spezielles Szenario haben, ist es mit ziemlicher Sicherheit der falsche Weg.

ThreadAbortException

0 Stimmen

Richtig, aber ich möchte, dass der Code unabhängig davon ausgeführt wird, ob die TAE ausgelöst wird oder nicht, also kann ich diese Logik nicht einfach in den TAE-Handler einfügen, und es wäre auch nicht sauber, sie zweimal zu implementieren. Im Grunde möchte ich vermeiden, dass ich "Back-Out"-Logik in meine catch- oder finally-Blöcke schreiben muss.

0 Stimmen

Ich bin mir nicht sicher, ob ich verstehe, dass sowohl der catch als auch der finally mit einer TAE-Ausnahme ausgeführt werden. Es wird nur am Ende eines Catch neu geworfen werden

2voto

mmx Punkte 400975

Lesen Sie über Eingeschränkte Ausführungsregionen .

Genauer gesagt, die Methode RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup wird hier nützlich sein.

0 Stimmen

Ich habe, und der einzige Vorteil, den es bietet, über das, was ich derzeit tun ist, dass es alle Ressourcen vor der Ausführung der finally-Block vorbereitet.

0 Stimmen

Eigentlich sind Sie CERs nicht nur für ThreadAbortException. Ich glaube nicht, dass es eine gute Idee ist, einen anwendungsspezifischen Code zu schreiben, der auf das Auftreten von ThreadAbortException angewiesen ist. Und im Grunde sind Finally-Blöcke dazu da, Ressourcen zu bereinigen, wobei CERs helfen, die Ausführung zu garantieren.

2voto

arul Punkte 13880

Ich glaube nicht, dass das möglich ist.

Warum müssen Sie die ThreadAbortException in erster Linie? Aufruf von thread.Abort() ist in der Regel ein Zeichen für schlechtes Design. Haben Sie eine Flag-Variable, die, wenn sie auf true gesetzt ist, einfach Rückkehr; von der Thread-Funktion, natürlich nach entsprechender Bereinigung.

Auf diese Weise müssen Sie sich nicht um die Ausnahme kümmern.

0 Stimmen

Sie machen ein gutes Argument über Thread.Abort(), aber die Neugestaltung dieses Aspekts unserer Anwendung könnte zu diesem Zeitpunkt zu riskant sein.

2voto

Hugh Punkte 21

Wenn der Aufruf von Thread.Abort ein schlechtes Design ist, warum ruft SQL Server ihn dann in einem Thread auf, in dem Benutzercode ausgeführt wird? Weil dies genau die Art und Weise ist, wie ein Abfrageabbruch gehandhabt wird, und es verursacht Alpträume.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X