例子:
Thread a: Interlocked.Increment(ref x);
Thread b: int currentValue = x;
假设线程 b 在线程 a 之后执行,线程 b 中的“currentValue”是否保证为增量值?或者,线程 b 是否需要执行 Thread.VolatileRead(ref x)?
例子:
Thread a: Interlocked.Increment(ref x);
Thread b: int currentValue = x;
假设线程 b 在线程 a 之后执行,线程 b 中的“currentValue”是否保证为增量值?或者,线程 b 是否需要执行 Thread.VolatileRead(ref x)?
从技术上讲,这取决于运行 .NET 的 CPU,但对于任何常见的 CPU,答案都是肯定的,Interlocked.Increment 保证缓存一致性。它充当MESI 要求的内存屏障。
CPU 可以在其缓存中包含无效的行,但它还不知道该行是无效的 - 无效队列包含尚未被执行的无效。(失效队列位于缓存的另一“边”;CPU 无法扫描它,因为它可以扫描存储缓冲区)。因此,需要内存屏障。
http://en.wikipedia.org/wiki/MESI_protocol (x86)
MOESI(用于 AMD64 芯片)非常相似:
据我了解,只有在其他 Interlocked 方法访问时才能保证 Interlocked。在 x86 系统上谈论 64 位值时,这可能尤其重要,因为它不能保证是原子的,因此撕裂值是一个问题。稳健地读取可由 Interlocked 更改的值的一个好技巧是 CompareExchange:
int val = Interlocked.CompareExchange(ref field, 0, 0);
这会将 的值field
变为 0,但前提是旧值为 0 - 否则它什么也不做。无论哪种方式,都会返回旧值。所以基本上:它读取值而不更改它,并且与其他互锁方法相比是安全的。