为什么Interlocked.Add没有超载接受双打作为参数?

时间:2009-09-09 15:41:52

标签: c# .net vb.net multithreading atomic

我完全理解Threading.Interlocked类提供的原子性;但是,我不明白为什么Add函数只提供两个重载:一个用于Integers,另一个用于Longs。为什么不使用双打或任何其他数字类型?

显然,更改Double的预期方法是CompareExchange;我认为这是因为修改Double比修改Integer更复杂。我还不清楚为什么,如果CompareExchange和Add都能接受整数,他们也不能同时接受双打。

4 个答案:

答案 0 :(得分:31)

其他人已经解决了“为什么?”。但是,使用Add(ref double, double)原语

来滚动自己的CompareExchange很容易
public static double Add(ref double location1, double value)
{
    double newCurrentValue = location1; // non-volatile read, so may be stale
    while (true)
    {
        double currentValue = newCurrentValue;
        double newValue = currentValue + value;
        newCurrentValue = Interlocked.CompareExchange(ref location1, newValue, currentValue);
        if (newCurrentValue == currentValue)
            return newValue;
    }
}
如果当前值等于CompareExchange,则

location1会将newValue的值设置为currentValue。正如它以原子,线程安全的方式这样做,我们可以单独依赖它而不需要求锁。

为什么while (true)循环?在实现乐观并发算法时,这样的循环是标准的。如果当前值与CompareExchange不同,则location1不会更改currentValue。我将currentValue初始化为location1 - 执行非易失性读取(可能是陈旧的,但这不会改变正确性,因为CompareExchange将检查值)。如果当前值(仍然)是我们从location读取的内容,则CompareExchange会将值更改为newValue。如果没有,我们必须使用CompareExchange返回的新当前值重试CompareExchange

如果该值被另一个线程更改,直到我们下一个CompareExchange的时间再次出现,它将再次失败,需要再次重试 - 这理论上可以永远继续,因此循环。除非您不断更改多个线程的值,否则CompareExchange很可能只会被调用一次,如果当前值仍然是location1的非易失性读取产生的,或者两次,如果它是不同。

答案 1 :(得分:25)

Interlocked类包含了Windows API Interlocked **函数。

反过来,它们使用x86的LOCK指令前缀环绕本机处理器API。它仅支持为以下指令添加前缀:

  

BT,BTS,BTR,BTC,XCHG,XADD,ADD,OR,ADC,SBB,AND,SUB,XOR,NOT,NEG,INC,DEC

你会注意到,这些反过来几乎映射到互锁的方法。不幸的是,这里不支持非整数类型的ADD函数。 64位平台支持64位长的添加。

这是一篇很棒的文章discussing lock semantics on the instruction level

答案 2 :(得分:7)

正如Reed Copsey所说,Interlocked操作映射(通过Windows API函数)到x86 / x64处理器直接支持的指令。鉴于其中一个函数是XCHG,您可以执行原子XCHG操作,而无需真正关心目标位置的位代表什么。换句话说,代码可以“假装”您正在交换的64位浮点数实际上是64位整数,并且XCHG指令不会知道差异。因此,.Net可以通过“假装”它们分别是整数和长整数来为浮点数和双精度数提供Interlocked.Exchange函数。

但是,所有其他操作实际上都对目标的各个位进行操作,因此除非值实际表示整数(或某些情况下的位数组),否则它们将无法工作。

答案 3 :(得分:1)

我怀疑有两个原因。

  1. .Net支持的处理器仅支持整数类型的互锁增量。我相信这是x86上的LOCK前缀,可能存在类似于其他处理器的指令。
  2. 如果一个浮点数加一个就可以得到相同的数字,所以我不确定你是否可以称之为增量。也许框架设计者在这种情况下试图避免非直观的行为。