为另一个问题写一个答案,一些有趣的事情出现了,现在我无法理解Interlocked.Increment(ref long value)
在 32 位系统上是如何工作的。让我解释。
在为 32 位环境编译时, NativeInterlockedIncrement64
现在不可用,好吧,这是有道理的,因为在 .NET 中,您无法根据需要对齐内存,并且可能会从托管调用它,然后他们将其删除。
在 .NET 中,我们可以Interlocked.Increment()
使用对 64 位变量的引用进行调用,我们仍然没有对其对齐的任何约束(例如在结构中,我们也可以使用FieldOffset
and StructLayout
)但是文档没有提到任何限制(AFAIK )。这很神奇,它有效!
Hans Passant 指出,这Interlocked.Increment()
是 JIT 编译器识别的一种特殊方法,它将发出对 COMInterlocked::ExchangeAdd64()的调用,然后调用FastInterlockExchangeAddLong ,这是InterlockedExchangeAdd64的宏,与InterlockedIncrement64具有相同的限制。
现在我很困惑。
忘记一秒钟的托管环境,回到原生环境。为什么InterlockedIncrement64
不能工作,但InterlockedExchangeAdd64
可以?InterlockedIncrement64
是一个宏,如果内在函数不可用并且InterlockedExchangeAdd64
可以工作,那么它可以作为对InterlockedExchangeAdd64
...的调用来实现
让我们回到托管:如何在 32 位系统上实现原子 64 位增量?我想句子“这个函数相对于对其他联锁函数的调用是原子的”很重要,但我仍然没有看到任何代码(感谢 Hans 指出更深层次的实现)来做到这一点。InterlockedExchangedAdd64
当内在函数不可用时,让我们从 WinBase.h 中选择实现:
FORCEINLINE
LONGLONG
InterlockedExchangeAdd64(
_Inout_ LONGLONG volatile *Addend,
_In_ LONGLONG Value
)
{
LONGLONG Old;
do {
Old = *Addend;
} while (InterlockedCompareExchange64(Addend,
Old + Value,
Old) != Old);
return Old;
}
读/写怎么能是原子的?