從IL認識關鍵字(四)


關鍵字

  上一篇研究了using關鍵字,在這篇我們研究一下lock關鍵字,在多線程,ASP.NET中涉及共享資源讀寫都會給線程代碼加鎖,保證資源正確讀寫。lock關鍵字結構也是try-finally結構。四篇隨筆有3篇(foreach的集合遍歷,using語句,lock語句)都是try-finally結構,在寫着幾篇文章時候,我發現以前處理finally考慮不全,所以還是熟悉最新的語法,使用它們不僅會使代碼更加整潔,而且使代碼更加健壯。

 

MSDN解釋

 lock 關鍵字將語句塊標記為臨界區,方法是獲取給定對象的互斥鎖,執行語句,然后釋放該鎖。

   一般線程加鎖,我們有如下幾個方法:

  1. lock關鍵字
  2. Monitor
  3. Mutex
  4. AutoResetEvent
  5. ManualResetEvent
  6. 其它  

  按照之前的經驗,C#的語法糖都不是新的東西,都是把現有的東西包裝一下,這里lock關鍵字究竟用哪個對象做線程同步,這里我們需要IL。

 

C# IL Code

   准備一個簡單的例子

void LockIL()
{
    lock(this)
    {
        Console.WriteLine("Hello World");
    }
}

   利用Reflector反編譯得出下面IL

.method private hidebysig instance void LockIL() cil managed
{
    .maxstack 2
    .locals init (
        [0] class Test.Program program)
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: dup 
    L_0003: stloc.0 
    L_0004: call void [mscorlib]System.Threading.Monitor::Enter(object)
    L_0009: nop 
    L_000a: nop 
    L_000b: ldstr "Hello World"
    L_0010: call void [mscorlib]System.Console::WriteLine(string)
    L_0015: nop 
    L_0016: nop 
    L_0017: leave.s L_0021
    L_0019: ldloc.0 
    L_001a: call void [mscorlib]System.Threading.Monitor::Exit(object)
    L_001f: nop 
    L_0020: endfinally 
    L_0021: nop 
    L_0022: ret 
    .try L_000a to L_0019 finally handler L_0019 to L_0021
}

   這段IL比較簡單,一個try-finally結構,在try之前Enter,try里面輸出(lock括號),finally里Exit。翻譯如下面代碼

void LockCode()
{
    Program program;
    System.Threading.Monitor.Enter(program = this);
    try
    {
        Console.WriteLine("Hello World");
    }
    finally
    {
        System.Threading.Monitor.Exit(program);
    }
}
V3.5

   這個是.Net3.5版本編譯下代碼,.Net4.0版本編譯代碼如下,IL代碼就不在這里貼出來,有興趣的園友可以自己反編譯看看。相對於3.5代碼,4.0的代碼更加合理,只有Enter調用成功才調用Exit。

void LockCode()
{
    bool flag = false;
    Program program = this;

    try
    {
        System.Threading.Monitor.Enter(program ,ref flag);
        Console.WriteLine("Hello World");
    }
    finally
    {
        if(flag == true)
        {
            System.Threading.Monitor.Exit(program);
        }
    }
}
V4.0

 

驗證

   下面簡單例子

static void Main(string[] args)
{
    lock (new object())
    {
    }
}

 

  利用VS性能測試工具得出調用方法

   從上圖可見,依次調用

  1. new object()
  2. System.Threading.Monitor.Enter(object)
  3. System.Threading.Monitor.Exit(object)

  從另外一個方面證明了lock關鍵字內部機制。

下一篇關鍵字

   以上只是本人的理解與實踐,如有錯誤不足之處希望理解包容,下一篇討論linq關鍵字。如(var from where ...),若篇幅不夠,開設多篇


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM