2009-08-31 7 views
15

Dupe:return statement in a lock procedure: inside or outsidePuis-je mettre une déclaration de retour dans une serrure

Le titre est un peu trompeur. Je sais que vous pouvez le faire, mais je m'interroge sur les implications de performance. Considérez ces deux blocs de code. (Pas de traitement d'erreur)

Ce bloc a le return extérieur de la serrure

public DownloadFile Dequeue() 
{ 
    DownloadFile toReturn = null; 
    lock (QueueModifierLockObject) 
    { 
     toReturn = queue[0]; 
     queue.RemoveAt(0); 
    } 
    return toReturn; 
} 

Ce bloc a la déclaration returnau sein la serrure

public DownloadFile Dequeue() 
{ 
    lock (QueueModifierLockObject) 
    { 
     DownloadFile toReturn = queue[0]; 
     queue.RemoveAt(0); 

     return toReturn; 
    } 
} 

est-il une différence dans le code ? Je comprends que les différences de performance (le cas échéant) seraient minimes, mais je me demande spécifiquement s'il y aurait une différence dans l'ordre que le lock se libère.

+1

* Sûrement * cela a déjà été couvert? – annakata

+0

Je n'ai pas pu trouver les résultats parce que je n'utilisais pas les bons termes de recherche avant. Oui, c'est une dupe. – DevinB

Répondre

24

Le compilateur C# déplacera la déclaration de retour à l'extérieur de la try/finally qui est créé pour la déclaration lock. Vos deux exemples sont identiques en termes de IL que le compilateur va émettre pour eux.

Voici un exemple simple prouvant que:

class Example 
{ 
    static Object obj = new Object(); 

    static int Foo() 
    { 
     lock (obj) 
     { 
      Console.WriteLine("Foo"); 
      return 1; 
     } 
    } 

    static int Bar() 
    { 
     lock (obj) 
     { 
      Console.WriteLine("Bar"); 
     } 
     return 2; 
    } 
} 

Le code est ci-dessus compilé à ce qui suit:

internal class Example 
{ 
     private static object obj; 

     static Example() 
     { 
       obj = new object(); 
       return; 
     } 

     public Example() 
     { 
       base..ctor(); 
       return; 
     } 

     private static int Bar() 
     { 
       int CS$1$0000; 
       object CS$2$0001; 
       Monitor.Enter(CS$2$0001 = obj); 
     Label_000E: 
       try 
       { 
         Console.WriteLine("Bar"); 
         goto Label_0025; 
       } 
       finally 
       { 
       Label_001D: 
         Monitor.Exit(CS$2$0001); 
       } 
     Label_0025: 
       CS$1$0000 = 2; 
     Label_002A: 
       return CS$1$0000; 
     } 

     private static int Foo() 
     { 
       int CS$1$0000; 
       object CS$2$0001; 
       Monitor.Enter(CS$2$0001 = obj); 
     Label_000E: 
       try 
       { 
         Console.WriteLine("Foo"); 
         CS$1$0000 = 1; 
         goto Label_0026; 
       } 
       finally 
       { 
       Label_001E: 
         Monitor.Exit(CS$2$0001); 
       } 
     Label_0026: 
       return CS$1$0000; 
     } 
} 

Comme vous pouvez le voir, le compilateur a pris la libery de déplacer le retour déclaration en Foo en dehors du try/finally.

+8

En effet. Et si vous regardez l'IL générée, vous verrez pourquoi nous faisons cela. Vous ne pouvez laisser qu'une région protégée avec une instruction spéciale "leave" qui sait comment nettoyer l'exception gérée par goo (ou, bien sûr, en lançant une exception). Vous ne pouvez pas faire des branches ordinaires ou des retours hors d'une région protégée. Par conséquent, nous devons générer des feuilles de la région protégée vers un retour généré en dehors de la région. –

2

Je crois que l'IL serait identique ... Je devrais le tester pour être sûr, mais l'instruction de verrouillage génère un essai finalement dans l'IL, et le retour déclencherait finalement (avec la version) AVANT que le cadre de la pile se ferme et retourne à l'appelant de toute façon, alors ...

0

Oui, mais pourquoi ne pas utiliser Dequeue?

Rappelez-vous de verrouillage est tout simplement un raccourci pour essentiellement quelque chose le long des lignes de:

 try 
     { 
      Monitor.Enter(QueueModifierLockObject); 

      DownloadFile toReturn = queue.Dequeue();   

      return toReturn; 
     } 
     finally 
     { 
      Monitor.Exit(QueueModifierLockObject); 
     } 
Questions connexes