2009-08-31 10 views
15

Dupe:return statement in a lock procedure: inside or outside¿Puedo poner una sentencia return dentro de una cerradura

El título es un poco engañoso. Sé que puedes hacerlo, pero me pregunto sobre las implicaciones de rendimiento.

considere estos dos bloques de código. (Sin control de errores)

Este bloque tiene la return fuera de la cerradura

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

Este bloque tiene la return comunicado dentro la cerradura

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

     return toReturn; 
    } 
} 

¿Hay alguna diferencia en el código ? Entiendo que las diferencias de rendimiento (si las hay) serían mínimas, pero me pregunto específicamente si habría una diferencia en el orden en que se libera el lock.

+1

* Seguramente * ¿esto ha sido cubierto antes? – annakata

+0

No pude encontrar los resultados porque antes no estaba usando los términos de búsqueda correctos. Sí, es una tontería. – DevinB

Respuesta

24

El compilador de C# moverá la instrucción de retorno fuera del try/finally que se crea para la declaración lock. Ambos ejemplos son idénticos en términos de IL que el compilador emitirá para ellos.

Aquí está un ejemplo simple demostrando 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; 
    } 
} 

El código anterior se compila a lo siguiente:

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; 
     } 
} 

Como se puede ver, el compilador ha tomado la libery de mover el regreso declaración en Foo fuera del try/finally.

+8

De hecho. Y si observas el IL generado, verás por qué lo hacemos. Solo puede salir de una región protegida con una instrucción especial de "abandono" que sepa cómo limpiar la excepción goo (o, por supuesto, lanzando una excepción). No puede hacer ramas ordinarias o retorna fuera de una región protegida. Por lo tanto, debemos generar hojas de la región protegida a un rendimiento generado fuera de la región. –

2

Creo que el IL sería idéntico ... Tendría que probarlo para estar seguro, pero la instrucción de bloqueo genera una prueba finalmente en el IL, y el retorno desencadenaría finalmente (con el lanzamiento) ANTES de que el marco de pila se cierre y regrese a la persona que llama de todos modos, entonces ...

0

Sí, pero ¿por qué no utilizar Dequeue?

Recuerde bloqueo es simplemente la abreviatura de algo esencialmente a lo largo de las líneas de:

 try 
     { 
      Monitor.Enter(QueueModifierLockObject); 

      DownloadFile toReturn = queue.Dequeue();   

      return toReturn; 
     } 
     finally 
     { 
      Monitor.Exit(QueueModifierLockObject); 
     } 
Cuestiones relacionadas