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%的性能,悲哀呀! 
    采集
  • 相关阅读:
    linux安装navicat全程记录
    MySQL5.7.20报错Access denied for user 'root'@'localhost' (using password: NO)
    java中的异步处理和Feature接口(一)
    @Autowired注解与@Resource注解的区别与用法
    超详细MySQL安装及基本使用教程
    linux下mysql开启远程访问权限及防火墙开放3306端口
    mysql之my.cnf详解
    centos7 mysql 启动mysqld.service
    linux系统安装mysql数据库
    ExecutorService 的理解与使用
  • 原文地址:https://www.cnblogs.com/wwwzzg168/p/4121547.html
Copyright © 2011-2022 走看看