2010-11-16 16 views
18

Ok, das ist ein seltsames Thema und ich hoffe, dass jemand etwas Licht abwerfen kann. Ich habe den folgenden Code:Blockiert schließlich nicht?

static void Main(string[] args) 
{ 
    try 
    { 
     Console.WriteLine("in try"); 
     throw new EncoderFallbackException(); 
    } 
    catch (Exception) 
    { 
     Console.WriteLine("in Catch"); 
     throw new AbandonedMutexException(); 
    } 
    finally 
    { 
     Console.WriteLine("in Finally"); 
     Console.ReadLine(); 
    } 
} 

jetzt, wenn ich kompilieren diese 3,5 (2,0 CLR) Ziel es wird ein Fenster sagen: „XXX funktioniert nicht mehr“ Pop-up. Wenn ich jetzt auf die Abbrechen Schaltfläche klicken, wird es endlich ausgeführt werden, UND wenn ich warte bis es fertig ist suchen und klicken Sie auf die Schließen Sie Programm Schaltfläche wird es auch endlich ausgeführt werden.

Nun, was interessant und verwirrend ist, wenn ich die gleiche Sache gegen 4.0 Durch Klicken auf die Schaltfläche Abbrechenkompiliert tun das schließlich blockieren und Klick auf das Programm schließen Taste laufen nicht.

Meine Frage ist: Warum läuft das schließlich auf 2,0 und nicht auf 4.0, wenn Sie die schließen Programm Knopf? Was sind die Auswirkungen davon?

EDIT: Ich führe dies von einer Eingabeaufforderung im Freigabemodus (im Freigabemodus gebaut) auf Windows 7 32 Bit. Fehlermeldung: Das erste Ergebnis unten läuft auf 3.5, schlägt nach dem Fenster, sucht nach dem Problem, das zweite ist, wenn ich es auf 4.0 ausführe und dasselbe mache.

alt text

+4

Wenn ich das mit .NET 4 kompiliere und es ausführe, erhalte ich den Standard-Windows-Fehlerbericht; Wenn ich das schließe oder auf "Nicht senden" klicke, druckt die Konsole "in Endlich" aus. Scheint gut zu funktionieren! –

+1

Führen Sie dies von Visual Studio aus? Versuchen Sie es manuell über die Eingabeaufforderung auszuführen. –

+0

Es könnte auch einen Unterschied zwischen 64/32 Systemen geben. – Kobi

Antwort

2

Ich glaube, das etwas mit Veränderungen zu tun hat, wie der Debugger angeschlossen ist.

Vom .NET Framework 4 Migration Issues Dokument:

Sie sind nicht mehr benachrichtigt, wenn der Debugger nicht anspringt, oder wenn es keine registrierten Debugger, der gestartet werden soll.

Was passiert ist, dass Sie den Debugger starten, aber Sie abbrechen. Ich glaube, das fällt unter diese Kategorie und die Anwendung hört einfach deswegen auf.

+0

Das Problem scheint ohne jeden beteiligten Debugger zu passieren. –

+0

Danke für die Info ist, dass ich das nicht wusste, aber ich führe dies nur von der Eingabeaufforderung aus –

+0

Die Fehlermeldung zeigt Zeilennummer, was darauf hindeutet, dass Sie die PDB-Datei auf dem gleichen Verzeichnis haben. Ich bin mir nicht sicher, ob es wichtig ist, ich kann es nicht reproduzieren. – Kobi

20

Ich bin in der Lage, das Verhalten jetzt zu reproduzieren (Ich habe nicht die genauen Schritte von Ihrer Frage erhalten, als ich es das erste Mal las).

Ein Unterschied, den ich beobachten kann, ist in der Art, wie die .NET-Laufzeit die unbehandelte Ausnahme handhabt. Die CLR 2.0 führt einen Helper namens Microsoft .NET Error Reporting Shim (dw20.exe), während die CLR 4.0 Windows Fehlerberichterstattung (WerFault.exe) gestartet wird.

Ich nehme an, dass die beiden unterschiedliche Verhalten in Bezug auf die Beendigung des Absturzes Prozess haben. WerFault.exe zerstört offensichtlich den .NET-Prozess sofort, während der .NET-Error-Reporting-Shim die Anwendung irgendwie schließt, so dass der finally-Block noch ausgeführt wird.

auch einen Blick auf die Ereignisanzeige haben: WerFault protokolliert einen Fehler in der Anwendung darüber informiert, dass der abgestürzte Prozess beendet wurde:

 
Application: ConsoleApplication1.exe 
Framework Version: v4.0.30319 
Description: The process was terminated due to an unhandled exception. 
Exception Info: System.Threading.AbandonedMutexException 
Stack: 
    at Program.Main(System.String[]) 

dw20.exe jedoch nur protokolliert ein Informationselement mit Ereignis-ID 1001 in das Ereignisprotokoll und beendet den Prozess nicht.

+0

Dies ist eine großartige Antwort !! –

0

Dies lief sowohl in Release und Debug, sowohl im Framework 3.5 und 4.0, ich sehe "in Finally" in allen Instanzen, ja von der Befehlszeile ausgeführt, ging bis zum Schließen meiner vs-Sitzungen, vielleicht ist es etwas auf Ihrem Maschine oder wie Kobi darauf hingewiesen, vielleicht Plattform bezogen (ich bin auf Win7 x64)

9

Denken Sie darüber nach, wie schrecklich diese Situation ist: etwas Unerwartetes ist passiert, dass niemand jemals Code geschrieben hat, um zu behandeln. Ist das Richtige in dieser Situation zu tun noch mehr Code laufen, das war wahrscheinlich auch nicht gebaut, um diese Situation zu behandeln? Möglicherweise nicht. Oft ist das Richtige, um hier zu tun ist nicht Versuch, die endlich Blöcke laufen, weil so eine schlechte Situation noch schlimmer machen wird. Du weißt bereits, dass der Prozess untergeht; lösche es sofort aus seinem Elend.

In einem Szenario, in dem eine unbehandelte Ausnahme den Prozess abbaut, kann irgendetwas passieren. Es ist implementationsdefiniert, was in diesem Fall passiert: ob der Fehler an die Windows-Fehlerberichterstattung gemeldet wird, ob ein Debugger gestartet wird und so weiter. Die CLR ist vollkommen in ihren Rechten, zu versuchen, endlich Blöcke zu laufen, und ist auch vollkommen in ihrem Recht, schnell zu versagen. In diesem Szenario sind alle Wetten aus; Verschiedene Implementierungen können verschiedene Dinge tun.

6

Alle meine Kenntnisse zu diesem Thema ist aus diesem Artikel hier entnommen: http://msdn.microsoft.com/en-us/magazine/cc793966.aspx - Bitte beachten Sie, es ist für .NET 2.0 geschrieben, aber ich habe das Gefühl, es macht Sinn für das, was wir in diesem Fall erlebt haben (mehr als "weil es beschlossen,“sowieso)

Quick‚ich habe nicht Zeit, dass Artikel‘Antwort zu lesen (obwohl Sie sollten, es ist ein wirklich gut ist):

die Lösung für das Problem (wenn Sie absolutly von Ihnen haben, schließlich blocks run) wäre, a) in einen globalen Fehlerhandler zu setzen oder b) .NET zu zwingen, immer endlich Blöcke laufen zu lassen und die Dinge so zu machen (wohl in die falsche Richtung) in .NET 1.1 - Platziere folgendes in deiner App .config:

<legacyUnhandledExceptionPolicy enabled="1"> 

Der Grund dafür: Wenn eine Ausnahme in .NET ausgelöst wird, beginnt es wieder durch den Stapel zu Fuß suchen Handler Ausnahme und wenn es eine findet es tut dann einen zweiten Weg zurück durch den Stapel läuft schließlich Blöcke vor läuft der Inhalt des Fangs. Wenn es keinen Catch findet, wird dieser zweite Weg nie ausgeführt, also werden die finally Blöcke niemals hier ausgeführt, weshalb ein globaler Ausnahmehandler immer finally-Klauseln ausführen wird, da die CLR sie ausführt, wenn sie den Catch findet, NICHT wenn er ihn ausführt (was ich glaube, bedeutet, auch wenn Sie einen Fang/werfen Sie Ihre endgültigen Blöcke werden immer noch laufen).

Der Grund für die Funktion app.config ist, weil für .NET 1.0 und 1.1 die CLR einen globalen Haken hatte, der Exceptions schlucken würde, bevor sie unmanaged würden, was natürlich ein Fang wäre, die endgültigen Blöcke auszulösen Lauf. Natürlich gibt es keine Möglichkeit, dass das Framework genug über diese Exception wissen kann, um es zu handhaben, nehmen Sie zum Beispiel einen Stack-Überlauf, also ist dies wahrscheinlich der falsche Weg, dies zu tun.

Das nächste Bit ist, wo es ein bisschen klebrig wird, und ich mache Annahmen basiert auf, was der Artikel hier sagt.

Wenn Sie in .NET 2.0 + ohne die traditionelle Ausnahmebehandlung arbeiten, dann würde Ihre Exception in das Windows-Ausnahmebehandlungssystem (SEH) fallen, das der CLR sehr ähnlich ist, da es durch Frames läuft bis es keinen Catch findet und dann eine Reihe von Ereignissen namens Unhandled Exception Filter (UEF) aufruft.Dies ist ein Ereignis, das Sie abonnieren können, aber es kann immer nur EINE Sache abonniert haben. Wenn also etwas Windows abonniert, übergibt es die Adresse des Rückrufs, der vorher dort war, und erlaubt Ihnen, eine Kette von UEF einzurichten Behandler - ABER SIE MÜSSEN DIESE Adresse NICHT HONNEN, sie sollten die Adresse selbst anrufen, aber wenn man die Kette bricht, bap, erhält man keine Fehlerbehandlung mehr. Ich nehme an, dass dies passiert, wenn Sie die Windows-Fehlerberichterstattung abbrechen, die UEF-Kette bricht, was bedeutet, dass die Anwendung sofort heruntergefahren wird und die endgültigen Blöcke nicht ausgeführt werden. Wenn Sie sie jedoch bis zum Ende laufen lassen und schließen, Es ruft den nächsten UEF in der Kette auf. .NET hat eine registriert, von der die AppDomain.UnhandledException aufgerufen wird (also auch dieses Ereignis ist nicht garantiert) was ich davon ausgehe ist auch, wo Sie Ihre zuletzt aufgerufenen Blöcke abrufen - da kann ich nicht sehen, wenn Sie nie übergehen Zurück in die CLR kann ein gemanagter finally-Block ausgeführt werden (der Artikel geht nicht in dieses Bit.)

+3

Serious OCD Moment dort .... Ich hätte das Büro vor 3 Stunden verlassen müssen. –

Verwandte Themen