zoukankan      html  css  js  c++  java
  • C#内部关于绑定事件Event的线程安全

    private EventHandler _FieldsChanged;
    public event EventHandler FieldsChanged
    {
        add
        {
            EventHandler handler2;
            EventHandler fieldsChanged = this._FieldsChanged;
            do
            {
                handler2 = fieldsChanged;
                EventHandler handler3 = (EventHandler)Delegate.Combine(handler2, value);
                fieldsChanged = Interlocked.CompareExchange<EventHandler>(ref this._FieldsChanged, handler3, handler2);
            }
            while (fieldsChanged != handler2);
        }
        remove
        {
            EventHandler handler2;
            EventHandler fieldsChanged = this._FieldsChanged;
            do
            {
                handler2 = fieldsChanged;
                EventHandler handler3 = (EventHandler)Delegate.Remove(handler2, value);
                fieldsChanged = Interlocked.CompareExchange<EventHandler>(ref this._FieldsChanged, handler3, handler2);
            }
            while (fieldsChanged != handler2);
        }
    }
        下面是我最后的理解,也许是错的:
    EventHandler handler2;
    EventHandler fieldsChanged = this._FieldsChanged;
    do
    {
        // 两个本地变量都保存着_FieldsChanged的本地引用
        handler2 = fieldsChanged;
        // 事件绑定。这是唯一一句业务代码
        EventHandler handler3 = (EventHandler)Delegate.Combine(handler2, value);
        // 如果_FieldsChanged等于handler2,就执行_FieldsChanged=handler3,这里是原子操作,线程安全
        // 如果不等,很明显,有线程冲突存在,数据被别的线程修改过了,这里返回_FieldsChanged到fieldsChanged中去
        fieldsChanged = Interlocked.CompareExchange<EventHandler>(ref this._FieldsChanged, handler3, handler2);
    }
    while (fieldsChanged != handler2);

    // 实际上,整个过程,如果不考虑线程安全,可以直接这么写
    _FieldsChanged = (EventHandler)Delegate.Combine(_FieldsChanged, value);
    // 这段代码的精妙之处就在于这个线程安全,如果Combine后,别的线程也进来,那就出现了数据丢失
    // 当然,常规做法可以是Lock住这段代码,但是,线程冲突的可行性不到1%,为此损失了99%的性能,悲哀呀! 
    采集
  • 相关阅读:
    Elixir 简介
    docker 基础
    函数式和面向对象
    react-native 简介及环境
    Ecto 总结
    使用 dep 配置 golang 开发环境
    docker 私有仓库简易搭建
    Elixir 单元测试
    基于资源的权限系统-API设计
    差商代微商的方法求解一阶常微分方程
  • 原文地址:https://www.cnblogs.com/wwwzzg168/p/4121547.html
Copyright © 2011-2022 走看看