Question

Je viens juste fini de lire « C # 4.0 in a Nutshell » (O'Reilly) et je pense qu'il est un grand livre pour un programmeur prêt à passer à C #, mais il me à me demander. Mon problème est la définition de la déclaration de using. Selon le livre (p. 138),

using (StreamReader reader = File.OpenText("file.txt")) {
    ...
}

est précisément équivalent à:

StreamReader reader = File.OpenText("file.txt");
try {
    ...
} finally {
    if (reader != null)
        ((IDisposable)reader).Dispose();
}

Supposons, cependant, que cela est vrai et que ce code est exécuté dans un thread séparé. Ce fil est maintenant abandonnée avec thread.Abort(), donc un ThreadAbortException est jeté et supposons que le fil est exactement après l'initialisation du lecteur et avant d'entrer dans la clause try..finally. Cela signifie que le lecteur n'est pas disposé!

Une solution possible serait de coder ainsi:

StreamReader reader = null;
try {
    reader = File.OpenText("file.txt");
    ...
} finally {
    if (reader != null)
        ((IDisposable)reader).Dispose();
}

Ce serait abort-safe.

Maintenant, pour mes questions:

  1. sont les auteurs du droit comptable et la déclaration de using n'est pas abort de sécurité ou sont-ils pas et il se comporte comme dans ma deuxième solution?
  2. Si using est équivalente à la première variante (non abort-safe), pourquoi est-il vérifier null dans finally?
  3. Selon le livre (p. 856), ThreadAbortException peut être jeté partout dans le code managé. Mais peut-être il y a des exceptions et la première variante est abort-sécurité après tout?

EDIT: Je sais que l'utilisation thread.Abort() est pas considérée comme une bonne pratique. Mon intérêt est purement théorique: comment la déclaration se comportent using exactement

Était-ce utile?

La solution

site Web compagnon du livre a plus d'informations sur les discussions .

En bref, la première traduction est correcte (vous pouvez dire en regardant l'IL).

La réponse à la deuxième question est qu'il peut y avoir des scénarios où la variable peut être légitimement nulle. Par exemple, getFoo () peut retourner null ici, où vous ne voudriez pas un NullReferenceException jeté dans le bloc finalement implicite:

using (var x = GetFoo())
{
   ...
}

Pour répondre à votre troisième question, la seule façon de sécuriser Abandonner (si vous appelez le code Framework) est de détruire le AppDomain après. Ceci est en fait une solution pratique dans de nombreux cas (c'est exactement ce que fait LINQPad chaque fois que vous annulez une requête en cours d'exécution).

Autres conseils

Il n'y a vraiment pas de différence entre vos deux scénarios -. Dans le second, le ThreadAbort pourrait encore se produire après l'appel à OpenText, mais avant que le résultat est attribué au lecteur

En fait, tous les paris sont quand vous obtenez un ThreadAbortException. Voilà pourquoi vous ne devriez jamais délibérément faire avorter les discussions plutôt que d'utiliser une autre méthode d'apporter gracieusement le fil à sa fin.

En réponse à votre édition - Je rappelle encore une fois que vos deux scénarios sont en fait identiques. La variable « lecteur » sera nulle, sauf si l'appel File.OpenText avec succès finalise et retourne une valeur, donc il n'y a pas de différence entre l'écriture du code la première manière par rapport à la seconde.

Thread.Abort est très très mauvais juju; si les gens appellent que vous êtes déjà dans beaucoup de problèmes (serrures irrécupérables, etc.). Thread.Abort devrait vraiment se limiter à la scanerio de inhuming un processus maladif.

Les exceptions sont généralement proprement Déroulé, mais dans les cas extrêmes, il n'y a aucune garantie que tous les bits de code peut exécuter. Un exemple plus pressant est « ce qui se passe en cas de panne? ».

Re le contrôle de null; si File.OpenText est revenu null? OK, il pas mais compilateur ne sait pas.

Un peu hors-sujet, mais le comportement de l'instruction de blocage lors de l'avortement fil est intéressant aussi. Bien que verrouillage est équivalent à:

object obj = x;
System.Threading.Monitor.Enter(obj);
try {
    …
}
finally {
    System.Threading.Monitor.Exit(obj);
}

Il est garanti (par le x86 JITter) que le fil ne se produit pas entre abort Monitor.Enter et l'instruction try.
http: // blogs .msdn.com / b / ericlippert / archive / 2007/08/17 / subtilités-de-c-il-codegen.aspx

Le code IL généré semble être différente en .net 4:
http: / /blogs.msdn.com/b/ericlippert/archive/2009/03/06/locks-and-exceptions-do-not-mix.aspx

La spécification de langage indique clairement que le premier est correct.

http://msdn.microsoft.com/en-us/vcsharp/ aa336809.aspx MS Spec (document Word)
http://www.ecma-international.org/publications /files/ECMA-ST/Ecma-334.pdf ECMA Spec

Dans le cas d'un fil les deux variantes de l'interruption du code peut échouer. Le second si l'interruption se produit après l'expression a été évaluée, mais avant l'affectation à la variable locale a eu lieu.

Mais vous ne devriez pas utiliser l'avortement de fil de toute façon, car il peut facilement corrompre l'état du appdomain. Alors que les discussions abort si vous forcez un appdomain décharge.

Vous l'accent sur le mauvais problème. Le ThreadAbortException est tout aussi susceptible d'abandonner la méthode OpenText (). Vous pourriez espérer qu'il est résistant à cela, mais ce n'est pas. Les méthodes cadres font pas ont des clauses try / catch qui tentent de faire face à une interruption de fil.

Prenez note que le fichier ne reste pas ouvert pour toujours. La volonté FileStream finaliseur, par la suite, fermez la poignée de fichier. Bien sûr, cela peut encore causer des exceptions dans votre programme en cours d'exécution quand vous gardez et essayez d'ouvrir à nouveau le fichier avant l'exécution finaliseur. Mais que cela est quelque chose que vous devez toujours être sur la défensive lorsque vous exécutez un système d'exploitation multi-tâches.

  

sont les auteurs du droit comptable et la déclaration à l'aide n'est pas abort de sécurité ou sont-ils pas et il se comporte comme dans ma deuxième solution?

     

Selon le livre (p. 856), ThreadAbortException peut être jeté partout dans le code managé. Mais peut-être il y a des exceptions et la première variante est abort-sécurité après tout?

Les auteurs ont raison. Le bloc using n'est pas Abandon- sûr. Votre deuxième solution est pas abort de sécurité, le fil peut être interrompu au milieu de l'acquisition des ressources.

Bien que ce n'est pas Abandon- sûr, tout usage unique qui a des ressources unmanged devrait également mettre en œuvre un finaliseur, qui éventuellement exécuter et nettoyer la ressource. Le finaliseur doit être suffisamment robuste pour aussi prendre soin de ne pas les objets complètement initialisés, dans le cas où le fil Abandonne au milieu de l'acquisition des ressources.

A Thread.Abort n'attendre l'exécution de code à l'intérieur Constrained Régions d'exécution (URCE), des blocs, des blocs de finally catch, constructeurs statiques et code non managé. C'est donc une solution abort-safe ( uniquement en ce qui concerne l'acquisition et la cession de la ressource):

StreamReader reader = null;
try {
  try { }
  finally { reader = File.OpenText("file.txt"); }
  // ...
}
finally {
  if (reader != null) reader.Dispose();
}

Mais être prudent , le code abort de sécurité devrait fonctionner rapide et ne pas bloquer . Il pourrait suspendre une opération de déchargement de domaine de l'application entière.

  

En cas d'utilisation est équivalente à la première variante (non abort-safe), pourquoi est-il vérifier null enfin?

Vérification de la valeur NULL rend le modèle de sécurité using en présence de références null.

L'ancien est en effet exactement équivalent à celui-ci.

Comme nous l'avons souligné, ThreadAbort est en effet une mauvaise chose, mais ce n'est pas tout à fait la même chose que tuer la tâche avec le Gestionnaire des tâches ou éteindre votre PC.

ThreadAbort est une exception gérée, que le temps d'exécution soulèvera quand il est possible, et alors seulement.

Cela dit, une fois que vous êtes dans ThreadAbort, pourquoi la peine d'essayer de nettoyage? Vous êtes dans agonise de toute façon.

finally-instruction est toujours exécutée, MSDN dit « enfin est utilisé pour garantir un bloc d'instructions de code d'exécutions quelle que soit la façon dont le bloc d'essai précédent est sorti. »

Alors, vous n'avez pas à vous soucier de ne pas les ressources nettoyage etc (seulement si les fenêtres, le Cadre-Runtime ou quoi que ce soit d'autre mauvais, vous ne pouvez pas contrôler qui se passe, mais il y a des problèmes plus graves que le nettoyage des ressources ;-))

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top