c# – 为什么Interlocked.CompareExchange仅支持引用类型?

前端之家收集整理的这篇文章主要介绍了c# – 为什么Interlocked.CompareExchange仅支持引用类型?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
免责声明:我的帖子显然总是很冗长.如果您碰巧知道标题问题的答案,请随时回答它而不阅读下面的扩展讨论.

System.Threading.Interlocked类提供了一些非常有用的方法来帮助编写线程安全的代码.其中一个更复杂的方法是CompareExchange,它可用于计算可从多个线程更新的运行总计.

由于使用CompareExchange有点棘手,我认为为它提供一些辅助方法是一个相当常识的想法:

// code mangled so as not to require horizontal scrolling
// (on my monitor,anyway)
public static double Aggregate
(ref double value,Func<double,double> aggregator) {
    double initial,aggregated;

    do {
        initial = value;
        aggregated = aggregator(initial);
    } while (
        initial != Interlocked.CompareExchange(ref value,aggregated,initial)
    );

    return aggregated;
}

public static double Increase(ref double value,double amount) {
    return Aggregate(ref value,delegate(double d) { return d + amount; });
}

public static double Decrease(ref double value,delegate(double d) { return d - amount; });
}

现在,也许我只是因为一般的快乐而感到愧疚(我承认,这通常是正确的);但是我觉得将上述方法提供的功能限制为仅加倍值(或者更确切地说,对于我必须为我想要支持的每种类型编写上述方法的重载版本)确实感到愚蠢.为什么我不能这样做?

// the code mangling continues...
public static T Aggregate<T>
(ref T value,Func<T,T> aggregator) where T : IEquatable<T> {
    T initial,aggregated;

    do {
        initial = value;
        aggregated = aggregator(initial);
    } while (
        !initial.Equals(
            Interlocked.CompareExchange<T>(ref value,initial)
        )
    );
}

我不能这样做因为Interlocked.CompareExchange< T>显然有一个T:class约束,我不明白为什么.也就是说,也许是因为CompareExchange已经有重载接受Int32,Int64,Double等;但这似乎不是一个很好的理由.例如,在我的情况下,能够使用Aggregate< T>是非常方便的.执行各种原子计算的方法.

解决方法

Interlocked.CompareExchange旨在使用处理器直接提供的本机原子指令来实现.这样的东西在内部使用锁(它是为无锁方案设计的)是没有意义的.

提供原子比较交换指令的处理器自然支持它作为小的“寄存器大小”操作(例如,英特尔x64处理器上的最大比较交换指令是cmpxchg16b,其工作在128位值).

任意值类型可能比这更大,并且使用单个指令进行比较 – 交换它可能是不可能的.比较交换参考类型很容易.无论内存中的总大小如何,您都将比较和复制已知大小的小指针.对于像Int32和Double这样的原始类型也是如此 – 它们都很小.

猜你在找的C#相关文章