当前位置: 移动技术网 > IT编程>开发语言>c# > 深入多线程之:深入分析Interlocked

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

2019年07月18日  | 移动技术网IT编程  | 我要评论
在大多数计算机上,增加变量操作不是一个原子操作,需要执行下列步骤:        一:将实例变量中的值加载到寄

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

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

       二:增加或减少该值。

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

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

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<tresult, targument>(int startvalue, targument argument,
            out tresult morphresult);

        static tresult morph<tresult, targument>(ref int target, targument argument,
            morpher<tresult, targument> 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;
        }


基本原理和上面的一致。

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网