2013-02-22 35 views
3

MSDN文章Thread Synchronization (C# Programming Guide)規定:爲什麼鎖確保底層顯示器已經發布,而直接使用顯示器卻沒有?

lock (x) 
{ 
    DoSomething(); 
} 

相當於:

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

,然後是:

「使用lock關鍵字通常優於使用Monitor 直接上課,... 因爲鎖確保底層顯示器 我s ^釋放,即使受保護的代碼拋出一個異常

請問這句話的意思是,最後的代碼片段,使用顯示器時,不保證」的基本顯示器被釋放,即使受保護的代碼拋出例外「?
爲什麼?

那麼,我很矛盾的互相矛盾的斷言「等效」,而不是(一個使用保證和另一個,等價,不)相同。

+0

太多太好的答案。太難確定哪個標記是正確的。謝謝大家! – Fulproof 2013-02-22 14:26:53

回答

3

如果你看看由4.0編譯器anycpu生成和反向的C#的clossest鎖equivelent實現我能得到的會是什麼樣的IL:

object x = new object(); 
bool lockTaken = false; 
// lock 
try{ 
    System.Threading.Monitor.Enter(x, ref lockTaken) 
    DoSomeThing(); 
} 
finally 
{ 
    if (lockTaken) 
    { 
     System.Threading.Monitor.Exit(x); 
    } 
} 

所有做是爲了防止在鎖被採取的情況下,一個線程中止,鎖永遠不會釋放,導致種族/僵局。警告告訴您基本上要平衡進入和退出呼叫的良好和失敗情況。鎖定語句是實現該目標的最簡單的抽象。在此基礎上IL

IL_0000: nop 
    IL_0001: ldc.i4.0 
    IL_0002: stloc.0 
    .try 
    { 
     IL_0003: ldsfld object p::x 
     IL_0008: dup 
     IL_0009: stloc.1 
     IL_000a: ldloca.s 0 
     IL_000c: call void [mscorlib]System.Threading.Monitor::Enter(object, bool&) 
     IL_0011: nop 
     IL_0012: nop 
     IL_0013: call void p::DoSomething() 
     IL_0018: nop 
     IL_0019: nop 
     IL_001a: leave.s IL_002c 
    } // end .try 
    finally 
    { 
     IL_001c: ldloc.0 
     IL_001d: ldc.i4.0 
     IL_001e: ceq 
     IL_0020: stloc.2 
     IL_0021: ldloc.2 
     IL_0022: brtrue.s IL_002b 

     IL_0024: ldloc.1 
     IL_0025: call void [mscorlib]System.Threading.Monitor::Exit(object) 
     IL_002a: nop 

     IL_002b: endfinally 
    } // end handler 

    IL_002c: nop 
    IL_002d: ldsfld object p::x 
    IL_0032: call void [mscorlib]System.Threading.Monitor::Enter(object) 
    IL_0037: nop 
    .try 
    { 
     IL_0038: nop 
     IL_0039: call void p::DoSomething() 
     IL_003e: nop 
     IL_003f: nop 
     IL_0040: leave.s IL_0050 
    } // end .try 
    finally 
    { 
     IL_0042: nop 
     IL_0043: ldsfld object p::x 
     IL_0048: call void [mscorlib]System.Threading.Monitor::Exit(object) 
     IL_004d: nop 
     IL_004e: nop 
     IL_004f: endfinally 
    } // end handler 

    IL_0050: nop 
    IL_0051: ret 
+0

謝謝你的胡言亂語IL :) – Fulproof 2013-02-23 03:42:28

3

如果鎖在功能上等同於所提供的代碼位,則顯然可以確保它將被釋放,因爲存在finally子句。 但是,如果您只是最終沒有使用monitor,您可能會遇到麻煩,導致死鎖。

至少,這就是我認爲這篇文章意味着它的解釋。

+0

這就是我的意思 – NDJ 2013-02-22 08:51:26

5

的黑體字指的情況是更多的東西是這樣的:

Monitor.Enter(obj); 
DoSomethingThatThrows(); 
Monitor.Exit(obj); 

那裏,沒有嘗試,最後引發異常將繞過Monitor.Exit電話。

2

這意味着當您使用顯示器時,您可能會忘記使用試用版

其實,你會遇到的人們,很多隻是用Monitor.Enter在塊和Monitor.Exit在塊結束的開始。
這並不保證Monitor.Exit發生,因爲異常會導致代碼停止在塊的中間運行。

3

在x64架構(直到根據J.Duffy VS2008的JIT - 在某些極端情況它仍然發生,編譯時Any CPU沒有/o+開關。)這是可能的IL指令是在Monitor.Enter和之間放Try聲明。如果堆棧指針位於此指令時發生異常,則不會釋放lock

lock關鍵字的代碼生成卻阻止了這種情況的發生。

這可能是他們爲什麼建議使用lock關鍵字。

參考文獻:

Monitor.Enter, Thread aborts