zoukankan      html  css  js  c++  java
  • 浅议“全局变量”、“多线程”和“编译器陷阱”

    今天偶然看到一段代码,也看到了作者对此的说明,觉得很有意思:
    public event EventHandler Started;

    protected virtual void OnStarted(EventArgs e)
    {
        EventHandler handler
    = Started;
       
    if (handler != null)
        {
            handler(
    null, e);
        }
    }

    为什么要申明一个全局的事件变量 Started?一开始我也觉得很多余,后来听作者说这段代码可以用到多线程中,有可能正在判断事件变量Started的时候,它有可能被另外的一个线程给改变了,这里引入一个局部变量 handler,可以保留Started之前的对象引用,确保后面的事件能够得到正确的处理。

    那么我们是否可以按照这个风格写下面类似的代码呢?

    public object MyObject;

    public  void OnFunction()
    {
        object obj
    = MyObject;
       
    if (obj!= null)
        {
            //在这里对obj进行其它处理

        }
    }

    上面这段代码在一般情况下没有问题,在多线程下面也工作良好,但如果你启用了编译器优化,很不幸,这段代码被优化成了下面的样子:

    public object MyObject;

    public  void OnFunction()
    {
       
    if (MyObject!= null)
        {
            //在这里对MyObject进行其它处理

        }
    }

    也就是说,MyObject 对象引用的代码被inline(内联)了,取消了局部变量object obj的定义,减少了对象数量和创建过程,有助于提高效率,如果这段代码被用于多线程中,噩梦很可能就来了,你不知道是谁修改了MyObject的值,这就是“编译器陷阱”!

    类似的代码,为什么上面EventHandler Started 在多线程下工作的很好,而object MyObject 却不可以?原来,这其中有玄机,在.NET平台中,它采用了不同的优化策略,参加原博文中的说法:

    如果我说,这样的代码明显是会被编译器优化掉的,因此这样写完全没有意义,怎样呢?毕竟EventHandler作为一个委托,并没有用volatile关键字声明(事实上事件不能声明为volatile,但可以在这里用Thread.VolatileRead(ref object)方法),使用时也没有用Interlocked来访问。我其实真没有想到那么远,不过CLR Via C#上给出了解释(记不得是哪一章了):JIT的编译器在这里会识别出这个写法并且确保不会把handler变量优化掉。真是万幸,但估计又成为了一个被学院派的诟病的特性。

    原文地址:

    再说说C#定义事件的写法
  • 相关阅读:
    Running ASP.NET Applications in Debian and Ubuntu using XSP and Mono
    .net extjs 封装
    ext direct spring
    install ubuntu tweak on ubuntu lts 10.04,this software is created by zhouding
    redis cookbook
    aptana eclipse plugin install on sts
    ubuntu open folderpath on terminal
    ubuntu install pae for the 32bit system 4g limited issue
    EXT Designer 正式版延长使用脚本
    用 Vagrant 快速建立開發環境
  • 原文地址:https://www.cnblogs.com/bluedoctor/p/2328036.html
Copyright © 2011-2022 走看看