2009-08-31 92 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); 
     }