• 从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 ...),若篇幅不够,开设多篇

  • 相关阅读:
    iOS 11 application 新特性
    Swift循环遍历集合方法
    Swift 使用 #warning
    swift 3.0 正则表达式查找/替换字符
    App Store 审核指南
    iOS 获取设备的各种信息的方法
    闭包(Closure)
    Swift的Guard语句
    Swift 学习指引
    Swift 4.0 废弃的柯里化
  • 原文地址:https://www.cnblogs.com/WilsonPan/p/2913847.html
Copyright © 2020-2023  润新知