2009-08-31 89 views
15

杜佩内:return statement in a lock procedure: inside or outside我可以把一个return语句锁

标题是有点误导。我知道你可以做到,但我想知道性能影响。

考虑这两个代码块。 (没有错误处理)

此块具有return外锁

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

此块具有return声明

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

     return toReturn; 
    } 
} 

的有代码中的任何差异?我明白性能差异(如果有的话)会很小,但我特别想知道lock获得发布的顺序是否会有所不同。

+1

*当然*这已被覆盖之前? – annakata 2009-08-31 20:22:14

+0

我找不到结果,因为我之前没有使用正确的搜索字词。是的,这是一个骗局。 – DevinB 2009-08-31 20:38:38

回答

24

C#编译器将移动return语句是为lock语句创建的try/finally之外。你的两个例子在编译器为它们发出的IL方面是相同的。

下面是一个简单的例子证明:

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

上面的代码被编译到以下几点:

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

正如你可以看到,编译器已经移动回归的libery在try/finally之外的Foo中声明。

+8

确实。如果你看看生成的IL,你会明白我们为什么要这么做。您只能通过特殊的“离开”指令来离开受保护的区域,该指令知道如何清理异常处理goo(当然还有抛出异常)。你不能做普通的分支或退出受保护的区域。因此,我们必须从受保护区域生成叶子,以便在区域外生成回程。 – 2009-08-31 22:40:05

2

我相信IL会是一样的......我不得不测试它是否可靠,但锁语句最终会在IL中生成一个try,并且返回将触发finally(随着发布)在堆栈帧关闭之前,无论如何返回给调用者,所以...

0

是的,但为什么不使用Dequeue?

记住锁简直是沿着线的基本的东西速记:

 try 
     { 
      Monitor.Enter(QueueModifierLockObject); 

      DownloadFile toReturn = queue.Dequeue();   

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