• 基元线程同步——Interlocked Anything模式


    上一篇基元线程同步——基础,非阻塞同步(VolatileRead,VolatileWrite,volatile,Interlocked) 已经对Interlocked类做了比较详细的分析,这一篇是对Interlocked类的一个模式进行补充说明。如果没用过Interlocked类,可以看看上面的这篇文章。

    这个模式的名字是Jeffrey给起的,它究竟要解决什么问题,我们为什么要用它?带着这些疑问,我们来看看它的应用场景。

    看看下面这个设定最大值的例子:

            private static Int32 Maximum(ref int target, int value)
            {
                int oldValue;
                oldValue = target;
    
                //计算最大值
                int temp = Math.Max(target, value);
    
                //注意:这里可能有其他线程恰好修改了target的值
    
                //如果target是oldValue,则替换成最大的值
                Interlocked.CompareExchange(ref target, temp, oldValue);
    
                return target;
            }

    测试代码:

                int v1 = 10;
    
                v1 = Maximum(ref v1, 20);
                Console.WriteLine("v1:" + v1);

    如果恰好有一个线程在Interlocked.CompareExchange这句代码执行前修改了target的值为15,那么我们这里的最大值20就不会生效,因为CompareExchange的比较条件将会失败。我们得到的输出,有可能是:v1:15。

    这样的结果可能不是我们的预期,问题在于上面的代码只调用了CompareExchange一次,如果不成功就跳过了这次修改。所以,我们可以考虑对CompareExchange做一个循环判断,不成功就再度尝试修改,直到成功为止。而这正是Jeffery所说的Interlock Anything模式。

    我们进一步修改上面的代码:

            private static Int32 Maximum(ref int target, int value)
            {
                int oldValue, currentValue;
    
                currentValue = target;
                do
                {
                    //oldValue记录当前循环开始时的原始值
                    oldValue = currentValue;
    
                    //计算最大值
                    int temp = Math.Max(target, value);
    
                    //注意:这里可能有其他线程恰好修改了target的值
    
                    //如果target是oldValue,则替换成最大的值。
                    //如果被其他线程修改了,currentValue返回的将会是被其他线程修改后的最新值,比如:15
                    currentValue = Interlocked.CompareExchange(ref target, temp, oldValue);
                }
                while (currentValue != oldValue);//如果被修该,则进入下一次循环,尝试再次修改
    
                return target;
            }

    注释中已经写得很清楚了,可能你需要反复的思考一下上面的代码,理解其意图。这里只是对Int32的值进行了修改,利用这个模式实际可以对任何引用类型的值进行修改。从而避免多线程访问共同变量带来的冲突。

    对于这个模式的应用,我们看看微软给我们的示范:在实现事件(Event)时是如何运用了这个模式的。

    首先定义下面的一个事件:

            public delegate bool UploadFileCompleteEventHander(string fileName);
            public event UploadFileCompleteEventHander UploadFileComplete;

    我们知道,事件本身还是用代理来实现的,只不过编译器帮我们做了这部分工作,反编译这个事件的代码:

    public event UploadFileCompleteEventHander UploadFileComplete
    {
        add
        {
            UploadFileCompleteEventHander hander2;
            UploadFileCompleteEventHander uploadFileComplete = this.UploadFileComplete;
            do
            {
                hander2 = uploadFileComplete;
                UploadFileCompleteEventHander hander3 = (UploadFileCompleteEventHander) Delegate.Combine(hander2, value);
                uploadFileComplete = Interlocked.CompareExchange<UploadFileCompleteEventHander>(ref this.UploadFileComplete, hander3, hander2);
            }
            while (uploadFileComplete != hander2);
        }
        remove
        {
            UploadFileCompleteEventHander hander2;
            UploadFileCompleteEventHander uploadFileComplete = this.UploadFileComplete;
            do
            {
                hander2 = uploadFileComplete;
                UploadFileCompleteEventHander hander3 = (UploadFileCompleteEventHander) Delegate.Remove(hander2, value);
                uploadFileComplete = Interlocked.CompareExchange<UploadFileCompleteEventHander>(ref this.UploadFileComplete, hander3, hander2);
            }
            while (uploadFileComplete != hander2);
        }
    }

    看见了吗,上面的add和Remove方法,对代理的添加和删除就是用的这个模式,多么经典。保证多个线程注册一个事件时,不会出现冲突。

    总结:

    1,一个变量可能被多线程访问时,可以考虑运用这个模式。

    2,它的速度比阻塞式同步,如lock等,要快很多。

    3,它能对任何类型的变量进行赋值,而不仅仅局限于Int32,等原子操作类型。

  • 相关阅读:
    技术分享 | app自动化测试(Android)–App 控件交互
    测试人生 | 疫情之下工资翻了2倍多,这4个月学习比工作8年学到的还多
    23 树——学习红黑树的捷径
    红黑树代码实现及注释
    工作的第二和第三年(201807~202005)
    使用nodejs的wxmnode模块,开发一个微信自动监控提醒功能,做个天气预报。
    难蚌
    基于.NetCore开发博客项目 StarBlog (12) Razor页面动态编译
    .NetCore实现图片缩放与裁剪 基于ImageSharp
    Serverless 时代下微服务应用全托管解决方案
  • 原文地址:https://www.cnblogs.com/xiashengwang/p/2661798.html
Copyright © 2020-2023  润新知