Enfin bloquer pas en cours d’exécution?

Ok, c’est un peu un problème étrange et j’espère que quelqu’un pourra nous éclairer un peu. J’ai le code suivant:

static void Main(ssortingng[] 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(); } } 

MAINTENANT, lorsque je comstackrai ceci vers la cible 3.5 (2.0 CLR), une fenêtre apparaît indiquant que “XXX a cessé de fonctionner”. Si je clique maintenant sur le bouton Annuler, il lancera enfin, ET si j’attends la fin de la recherche, je clique sur le bouton Fermer le programme pour lancer également.

Maintenant, ce qui est intéressant et déroutant, c’est SI SI je fais la même chose que celle compilée contre 4.0 En cliquant sur le bouton Annuler , le bloc finally sera exécuté et en cliquant sur le bouton Fermer le programme, ce ne sera pas le cas.

Ma question est la suivante: pourquoi le programme final fonctionne-t-il en version 2.0 et non en version 4.0 lorsque vous appuyez sur le bouton Fermer le programme ? Quelles sont les répercussions de cela?

EDIT: Je l’exécute à partir d’une invite de commande en mode release (intégré en mode release) sur Windows 7 32 bits. Message d’erreur: Le premier résultat ci-dessous est en cours d’exécution sur 3.5, après la recherche de problème par Windows, le deuxième but est de l’exécuter sous 4.0 et de faire la même chose.

texte alternatif

Je suis capable de reproduire le comportement maintenant (je n’ai pas compris les étapes exactes de votre question lorsque je le lisais pour la première fois).

Une différence que je peux observer est dans la façon dont le runtime .NET gère l’exception non gérée. Le CLR 2.0 exécute un utilitaire appelé Microsoft .NET Error Reporting Shim ( dw20.exe ) alors que le CLR 4.0 démarre le rapport d’erreurs Windows ( WerFault.exe ).

Je suppose que les deux ont un comportement différent en ce qui concerne la fin du processus de blocage. WerFault.exe tue évidemment le processus .NET immédiatement alors que le rapport d’erreur .NET Shim ferme en quelque sorte l’application pour que le bloc finally soit toujours exécuté.

Consultez également l’observateur d’événements: WerFault enregistre une erreur d’application signalant que le processus bloqué s’est terminé:

 Application: ConsoleApplication1.exe
 Version du framework: v4.0.30319
 Description: le processus a été arrêté en raison d’une exception non gérée.
 Informations sur les exceptions: System.Threading.AbandonedMutexException
 Emstackr:
    à Program.Main (System.Ssortingng [])

Cependant, dw20.exe enregistre uniquement un élément d’information portant l’ID d’événement 1001 dans le journal des événements et ne met pas fin au processus.

Réfléchissez à la gravité de cette situation: il s’est produit quelque chose d’inattendu que personne n’a jamais écrit de code à gérer. Est-ce la bonne chose à faire dans cette situation d’ exécuter encore plus de code , qui n’était probablement pas non plus conçu pour gérer cette situation? Peut-être pas. Souvent, la bonne chose à faire ici est de ne pas essayer de gérer les blocages finaux, car cela aggraverait encore la situation. Vous savez déjà que le processus est en train de se terminer; mettez-le immédiatement hors de sa misère.

Dans un scénario où une exception non gérée va ralentir le processus, tout peut arriver. Ce qui se produit dans ce cas est défini par l’implémentation: si l’erreur est rapscope dans le rapport d’erreurs Windows, si un débogueur démarre, etc. Le CLR a parfaitement le droit d’essayer de lancer des blocs, mais il a également parfaitement le droit d’échouer rapidement. Dans ce scénario, tous les paris sont ouverts; différentes implémentations peuvent choisir de faire différentes choses.

Toutes mes connaissances sur ce sujet sont tirées de cet article ici: http://msdn.microsoft.com/en-us/magazine/cc793966.aspx – notez que cela est écrit pour .NET 2.0, mais j’ai le sentiment que c’est logique. pour ce que nous vivions dans ce cas (plus que “parce qu’il a décidé de” de toute façon)

Réponse rapide “Je n’ai pas le temps de lire cet article” (bien que vous deviez le faire, c’est un très bon):

La solution au problème (si vous devez absolument exécuter vos derniers blocs) serait de a) mettre en place un gestionnaire d’erreurs global ou b) de forcer .NET à toujours exécuter les derniers blocs et à faire les choses comme il l’a fait (sans doute le mauvais manière) dans .NET 1.1 – Placez ce qui suit dans votre app.config:

  

La raison: quand une exception est lancée dans .NET, il retourne dans la stack à la recherche de gestionnaires d’exception et, s’il en trouve un, retourne dans la stack en exécutant finalement les blocs avant d’ exécuter le contenu de la capture. S’il ne trouve pas d’attrapé, alors cette deuxième marche ne se produit jamais. Les blocs finaux ne sont jamais exécutés ici. C’est pourquoi un gestionnaire d’exceptions global exécutera toujours les clauses de fin, car le CLR les exécutera lorsqu’il trouvera l’attrape, PAS lorsqu’il l’exécutera. (ce qui, je crois, signifie que même si vous faites un attrapé / un lancer, vos blocs finaux seront toujours courus).

Le correctif app.config fonctionne parce que, pour .NET 1.0 et 1.1, le CLR contenait une capture globale qui engloutirait Exceptions avant de devenir non gérée, ce qui déclencherait l’exécution des derniers blocs, bien sûr. Bien sûr, il n’ya aucun moyen que le framework en sache assez sur ladite exception pour le gérer, prenons par exemple un débordement de stack, c’est donc probablement la mauvaise façon de le faire.

La partie suivante est celle où cela devient un peu collant, et je fais des suppositions basées sur ce que l’article dit ici.

Si vous êtes dans .NET 2.0+ sans la gestion des exceptions héritée, votre exception tomberait dans le système de gestion des exceptions de Windows (SEH) de Windows, qui semble très similaire au système CLR, dans la mesure où il retourne dans les frameworks jusqu’à ce qu’il ne soit plus recherchez une capture, puis appelle une série d’événements appelée filtre d’exception non gérée (UEF). Il s’agit d’un événement auquel vous pouvez vous abonner, mais il ne peut y avoir qu’une seule chose souscrite à la fois. Par conséquent, lorsqu’un abonnement est souscrit, Windows lui donne l’adresse du rappel précédent, ce qui vous permet de configurer une chaîne d’UEF. gestionnaires – MAIS ILS N’ONT PAS À HONORER cette adresse, ils doivent appeler l’adresse eux-mêmes, mais si l’un d’eux casse la chaîne, bap, vous n’obtiendrez plus de traitement d’erreur. Je suppose que c’est ce qui se passe lorsque vous annulez le rapport d’erreur Windows, cela rompt la chaîne UEF, ce qui signifie que l’application est immédiatement arrêtée et que les blocs finaux ne sont pas exécutés. Toutefois, si vous le laissez fonctionner jusqu’à la fin, il appellera la prochaine UEF de la chaîne. .NET aura enregistré celui qui est la raison pour laquelle AppDomain.UnhandledException est appelé (donc même cet événement n’est pas garanti), ce qui, je suppose, est également celui où vous obtenez vos derniers blocs appelés – car je ne vois pas comment si vous ne faites jamais une transition. de nouveau dans le CLR, un bloc enfin géré peut être exécuté (l’article ne va pas dans ce bit).

Je crois que cela a quelque chose à voir avec les changements apportés à la manière dont le débogueur est attaché.

Dans le document Problèmes de migration .NET Framework 4 :

Vous n’êtes plus averti lorsque le débogueur ne parvient pas à démarrer ou lorsqu’il n’y a pas de débogueur enregistré à démarrer.

En réalité, vous choisissez de démarrer le débogueur, mais vous l’annulez. Je crois que cela entre dans cette catégorie et que l’application s’arrête pour cette raison.

A couru dans les versions et le débogage, dans les frameworks 3.5 et 4.0, je vois “dans Enfin” dans tous les cas, oui en l’exécutant depuis la ligne de commande, est allé jusqu’à fermer mes sessions vs, peut-être quelque chose sur votre machine ou en tant que Kobi a souligné, peut-être lié à la plate-forme (je suis sur Win7 x64)