10

我知道 .NET 内存模型(在 .NET Framework 上;不是 compact/micro/silverlight/mono/xna/what-have-you)保证对于某些类型(最显着的原始整数和引用)操作保证是原子。

此外,我相信 x86/x64 测试和设置指令 (and Interlocked.CompareExchange) 实际上引用了全局内存位置,因此如果它成功,另一个Interlocked.CompareExchange会看到新值。

最后,我相信该volatile关键字是对编译器的指令,以尽快传播读取和写入,并且不对有关此变量的操作重新排序(对吗?)。

这导致了几个问题:

  1. 我上面的信念是正确的吗?
  2. Interlocked.Read没有 int 的重载,仅适用于 longs(这是 2 个 WORD,因此通常不会以原子方式读取)。我一直认为 .NET 内存模型保证在读取整数/引用时会看到最新的值,但是对于处理器缓存、寄存器等。我开始看到这可能是不可能的。那么有没有办法强制重新获取变量?
  3. volatile 足以解决整数和引用的上述问题吗?
  4. 在 x86/x64 上,我可以假设...

如果有两个全局整数变量 x 和 y,如果我写的话,都初始化为 0:

x = 1;
y = 2;

该 NO 线程将看到 x = 0 和 y = 2(即写入将按顺序发生)。如果它们不稳定,这会改变吗?

4

3 回答 3

6
  • 只有对最多 32 位宽(在 x64 系统上为 64 位宽)的变量的读取和写入是原子的。这意味着您不会读取int并获得半写的值。这并不意味着算术是原子的。
  • 互锁操作也充当内存屏障,所以是的,Interlocked.CompareExchange将看到更新的值。
  • 请参阅此页面。不稳定并不意味着有序。一些编译器可能选择不对 volatile 变量的操作重新排序,但 CPU 可以自由地重新排序。如果要阻止 CPU 重新排序指令,请使用(完整)内存屏障。
  • 内存模型确保读取和写入是原子的,使用 volatile 关键字可确保读取始终来自内存,而不是来自寄存器。所以你看到最新的值。这是因为 x86 CPU 会在适当的时候使高速缓存失效 - 请参阅thisthis。此外,请参阅InterlockedCompareExchange64了解如何以原子方式读取 64 位值。
  • 最后,最后一个问题。答案是线程实际上可以看到x = 0and y = 2,并且使用 volatile 关键字不会改变这一点,因为 CPU 可以自由地重新排序指令。你需要一个内存屏障。

概括:

  1. 编译器可以自由地重新排序指令。
  2. CPU 可以自由地重新排序指令。
  3. 字大小的读取和写入是原子的。算术和其他操作不是原子的,因为它们涉及读取、计算和写入。
  4. 从内存中读取的字大小将始终检索最新值。但大多数时候你不知道你是否真的从记忆中阅读。
  5. 完整的内存屏障停止 (1) 和 (2)。大多数编译器允许您自行停止 (1)。
  6. volatile 关键字确保您从内存中读取 - (4)。
  7. 互锁操作(锁定前缀)允许多个操作是原子的。例如,一个读+写(InterlockedExchange)。或者读+比较+写(InterlockedCompareExchange)。它们还充当内存屏障,因此 (1) 和 (2) 被停止。他们总是写入内存(显然),所以(4)是确保的。
于 2010-01-23T00:22:38.043 回答
2

遇到了这个旧线程。Hans 和 wj32 的答案都是正确的,除了关于volatile.

特别是关于你的问题

在 x86/x64 上,我可以假设...如果有两个全局整数变量 x 和 y,如果我写的话,它们都初始化为 0: x = 1; y = 2;

该 NO 线程将看到 x = 0 和 y = 2(即写入将按顺序发生)。如果它们不稳定,这会改变吗?

如果y是 volatile ,则写入x保证在写入 之前发生y,因此没有线程会看到x = 0and y = 2。这是因为对 volatile 变量的写入具有“释放语义”(逻辑上等同于释放栅栏的发射),即在它不会移动之前的所有读/写指令都不会通过它。(这意味着如果 x 是 volatile 而 y 不是,您可能仍会看到意外的x = 0和。)有关更多详细信息,请参阅C# 规范y = 2中的描述和代码示例。

于 2010-06-08T10:11:15.210 回答
0

不, volatile 关键字和原子性保证太弱了。您需要一个内存屏障来确保这一点。您可以使用 Thread.MemoryBarrier() 方法显式获取一个。

于 2010-01-20T10:49:07.063 回答