当前位置:  编程技术>.net/c#/asp.net

深入多线程之:深入分析Interlocked

    来源: 互联网  发布时间:2014-10-20

    本文导语:  在大多数计算机上,增加变量操作不是一个原子操作,需要执行下列步骤:        一:将实例变量中的值加载到寄存器中。        二:增加或减少该值。        三:在实例变量中存储该值。 在多线程环境下,线程会...

在大多数计算机上,增加变量操作不是一个原子操作,需要执行下列步骤:

       一:将实例变量中的值加载到寄存器中。

       二:增加或减少该值。

       三:在实例变量中存储该值。

在多线程环境下,线程会在执行完前两个步骤后被抢先。然后由另一个线程执行所有三个步骤,当第一个线程重新开始执行时,它覆盖实例变量中的值,造成第二个线程执行增减操作的结果丢失。

Interlocked可以为多个线程共享的变量提供原子操作。

    Interlocked.Increment:以原子操作的形式递增指定变量的值并存储结果。
    Interlocked.Decrement以原子操作的形式递减指定变量的值并存储结果。
    Interlocked.Add以原子操作的形式,添加两个整数并用两者的和替换第一个整数

但是Interlocked并没有为乘法,除法提供原子操作。那么如何实现乘法,除法,以及为其他的一些非原子操作提供原子操作的支持呢??


关键就在于Interlocked.CompareExchange 中,Jeffrey Richter把它叫做InterLocked Anything 模式。

下面我们使用Interlocked.CompareExchange 实现求最大值的原子操作。

代码如下:

public static int Maximum(ref int target, int value)
        {
            int currentVal = target;   //将target的当前值保存到currentVal中
            int startVal, desiredVal;  //声明两个变量来记录操作开始前的值和期望的结果值。

            do
            {
                startVal = currentVal; //将currentVal中的值保存到startVal中,此时记录的是target在操作开始前的最初值。
                desiredVal = Math.Max(startVal, value); //通过startVal进行复杂的计算,返回一个期望的结果,在这里仅仅是返回两者的最大值。

                //线程可能在这里被抢占,target的值可能被改变
                //如果target的值被改变了,那么target和startVal的值就不想等,所以就不应该用desiredVal替换target.
                //如果target的值没有被改变,那么target和startVal的值就像等,使用desiredVal替换target.
                //不管替换或者不替换,CompareExchange的返回值始终是target的值,所以currentVal的值现在是target的最新值。

                //CompareExchange:将target和startVal的值比较,相等则用desiredVal替换,否则不操作,
                //不管替换还是不替换返回的都是原来保存在target的值。
                currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal);
            } while (startVal != currentVal); //当target的起始值和最新值不相等的时候,说明target被修改了,所以继续下次判断,否则退出循环。
            return desiredVal;
        }


这段代码的核心就是:currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal);
// 将target的值和startVal的值比较,相等则用desiredVal替换target,否则不操作,
//不管替换还是不替换返回的都是原来保存在target的值。

在这里,计算可能会比较复杂,而不像上面的Math.Max一样,所以可以使用委托调用的方式进行封装。

代码如下:

delegate int Morpher(int startValue, TArgument argument,
            out TResult morphResult);

        static TResult Morph(ref int target, TArgument argument,
            Morpher morpher)
        {
            TResult morphResult;

            int currentVal = target, startVal, desiredVal;

            do
            {
                startVal = currentVal;
                desiredVal = morpher(startVal, argument, out morphResult);
                currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal);
            } while (startVal != currentVal);

            return morphResult;
        }


基本原理和上面的一致。

    
 
 

您可能感兴趣的文章:

  • 如何深入了解线程
  • 深入多线程之:解析线程的交会(Thread Rendezvous)详解
  • 深入分析父子线程、进程终止顺序不同产生的结果
  • 深入多线程之:深入生产者、消费者队列分析
  • 深入多线程之:双向信号与竞赛的用法分析
  • 深入多线程之:用Wait与Pulse模拟一些同步构造的应用详解
  • 深入Java线程中断的本质与编程原则的概述
  • 深入SQLite多线程的使用总结详解
  • 深入理解线程安全与Singleton
  • 深入多线程之:Wait与Pulse的使用详解
  • 深入探讨linux下进程的最大线程数、进程最大数、进程打开的文件数
  • Java 多线程同步 锁机制与synchronized深入解析
  • 深入Sqlite多线程入库的问题
  • 深入多线程之:Reader与Write Locks(读写锁)的使用详解
  • 深入Android线程的相关问题解惑
  • 深入java线程池的使用详解
  • 深入Android Handler与线程间通信ITC的详解
  • Java线程中断的本质深入理解
  • Android开发笔记之:深入理解多线程AsyncTask
  • 深入多线程之:内存栅栏与volatile关键字的使用分析
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • Docker支持更深入的容器日志分析
  • 关于《深入浅出MFC》
  • Linux有没有什么好的高级的书,我要深入,
  • 深入理解linux内核
  • [100分]有没有关于binutils的深入的资料?或者深入底层的资料?
  • 深入理解PHP内核 TIPI
  • 想深入学习Java应该学习哪些东西
  • 哪位有《JSP深入编程》电子版?
  • 想要深入学习LINUX该学什么?
  • 100分求:哪儿有《深入理解linux内核》可供下哉!
  • 如何深入Linux的内核学习?
  • U-BOOT得掌握到什么程序,用不用深入去学
  • 想深入了解操作系统该怎么做
  • 前一阵子学习了shell脚本,如果想深入点了解linux可以看什么书呢
  • 问一个《深入理解计算机系统》中的问题
  • ##想买书深入学习linux下的编程,请指教
  • 深入JDBC sqlserver连接写法的详解
  • 深入oracle特定信息排序的分析
  • 深入分析C中不安全的sprintf与strcpy
  • 哪儿有下载《深入理解Linux内核》这本书?(中文)
  • 请问JFC是否有必要深入研究?


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3