c# - 为什么 Interlocked.CompareExchange<T> 只支持引用类型?

标签 c# .net multithreading interlocked

免责声明:我的帖子显然总是很冗长。如果您碰巧知道标题问题的答案,请随意回答,而无需阅读我下面的扩展讨论。


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, double amount) {
    return Aggregate(ref value, delegate(double d) { return d - amount; });
}

现在,也许我只是对通用快乐感到内疚(我承认,这通常是真的);但是 对我来说 将上述方法提供的功能限制为 double 确实很愚蠢仅值(或者更准确地说,我必须为我想要支持的每种类型编写上述方法的重载版本)。为什么我不能这样做?

// 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, aggregated, initial)
        )
    );
}

我不能这样做因为 Interlocked.CompareExchange<T>显然有一个 where T : class约束,我不明白为什么。我的意思是,可能是因为 CompareExchange 已经过载了接受 Int32 , Int64 , Double , ETC。;但这似乎不是一个好的理由。例如,在我的例子中,能够使用 Aggregate<T> 会非常方便。执行各种原子计算的方法。

最佳答案

Interlocked.CompareExchange 旨在使用处理器直接提供的 native 原子指令来实现。让类似的东西在内部使用 lock 是没有意义的(它是为无锁场景设计的)。

提供原子比较交换指令的处理器自然支持它作为小型“寄存器大小”操作(例如,Intel x64 处理器上最大的比较交换指令是 cmpxchg16b,它适用于 128 位值).

任意值类型可能比它更大,并且比较交换它可能无法通过一条指令实现。比较交换引用类型很容易。不管它在内存中的总大小如何,您都将比较和复制一个已知大小的小指针。对于 Int32Double 等基本类型也是如此——它们都很小。

关于c# - 为什么 Interlocked.CompareExchange<T> 只支持引用类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2241553/

相关文章:

c# - PInvoke c++ dll from c# - 尝试加载格式不正确的程序。 (来自 HRESULT : 0x8007000B) 的异常

.net - 如何测量用于 .NET 远程处理的 IP 端口的输入/输出字节数?

java - 为什么要对字符串或其他对象使用 wait 方法?

android - 在重新获得焦点之前无法完成暂停的 Activity

c# - 如果一个对象没有静态字段,我是否需要担心它是线程安全的?

c# - 客户端 WCF 异常处理程序

c# - .NET Framework 4.5 - EF 从 MySQL 数据库中排除 "ufloat"列

c# - 使用 RestSharp 将 GET 参数添加到 POST 请求

带有 "watchdog"的 Ruby 线程

c# - 绑定(bind)到来自两个不同 ViewModel 的两个属性的差异