.NET 内存模型、易失性变量以及测试和设置:保证什么?
我知道.NET内存模型(在.NET框架上;不是compact/micro/silverlight/mono/xna/what-have-you)保证对于某些类型(最显着的是原始整数和引用)操作保证是原子。
此外,我相信 x86/x64 测试和设置指令(和 Interlocked.CompareExchange )实际上引用了全局内存位置,因此如果它成功另一个 Interlocked.CompareExchange ,会看到新的值。
最后,我相信 volatile 关键字是编译器传播读取和读取的指令。尽快写入并且不重新排序与此变量相关的操作(对吗?)。
这引出了几个问题:
- 我的上述信念正确吗?
- Interlocked.Read 没有 int 重载,只有 long 重载(它们是 2 个字,因此通常不会以原子方式读取)。我一直认为 .NET 内存模型保证在读取整数/引用时会看到最新的值,但是对于处理器缓存、寄存器等。我开始发现这可能是不可能的。那么有没有办法强制重新获取变量呢?
- 对于整数和引用来说,挥发性足以解决上述问题吗?
- 在 x86/x64 上,我可以假设...
如果有两个全局整数变量 x 和 y,都初始化为 0,如果我写:
x = 1;
y = 2;
没有线程会看到 x = 0 和 y = 2 (即写入将发生在命令)。如果它们不稳定,这会改变吗?
I know that the .NET memory model (on the .NET Framework; not compact/micro/silverlight/mono/xna/what-have-you) guaranteed that for certain types (most notably primitive integers and references) operations were guaranteed to be atomic.
Further, I believe that the x86/x64 test-and-set instruction (and Interlocked.CompareExchange
) actually references the global memory location, so if it succeeds another Interlocked.CompareExchange
would see the new value.
Finally, I believe that the volatile
keyword is an instruction to the compiler to propagate reads & writes ASAP and to not reorder operations concerning this variable (right?).
This leads to a few questions:
- Are my beliefs above correct?
Interlocked.Read
does not have an overload for int, only for longs (which are 2 WORDs and thus are not normally read atomically). I always assumed that the .NET memory model guaranteed that the newest value would be seen when reading ints/references, however with processor caches, registers, etc. I'm starting to see this may not be possible. So is there a way to force the variable to be re-fetched?- Is volatile sufficient to solve the above problem for integers and references?
- On x86/x64 can I assume that...
If there are two global integer variables x and y, both initialized to 0 that if I write:
x = 1;
y = 2;
That NO thread will see x = 0 and y = 2 (i.e. the writes will occur in order). Does this change if they are volatile?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
x = 0
和y = 2
,并且使用 volatile 关键字不会改变这一点,因为 CPU 可以自由地重新排序指示。你需要一个记忆屏障。摘要:
Interlocked.CompareExchange
will see the updated value.x = 0
andy = 2
, and using the volatile keyword doesn't change that because the CPU is free to re-order instructions. You need a memory barrier.Summary:
遇到了这个旧线程。 Hans 和 wj32 的答案都是正确的,除了关于
易失性
的部分。具体针对你的问题
如果
y
是易失性的,则保证对x
的写入发生在对y
的写入之前,因此没有线程会看到x = 0 和 y = 2。这是因为对易失性变量的写入具有“释放语义”(逻辑上相当于释放栅栏的发射),即在它之前的所有读/写指令都不会通过它。 (这意味着如果 x 是易失性的,但 y 不是易失性的,您可能仍然会看到意外的
x = 0
和y = 2
。) C# 规范中的代码示例更多细节。Came across this old thread. The answers from Hans and wj32 are all correct except for the part regarding
volatile
.Specifically regarding your question
If
y
is volatile, the write tox
is guarantee to happen before the write toy
, therefore no thread will ever seex = 0
andy = 2
. That is because the write to a volatile variable has the "release semantic" (logically equivalent to the emission of a release fence), i.e. all read/write instructions before it won't move pass it. (This implies that if x is volatile but y is not, you might still see the unexpectedx = 0
andy = 2
.) See the description & code example in the C# spec for more details.不,易失性关键字和原子性保证太弱了。你需要一个内存屏障来确保这一点。您可以使用 Thread.MemoryBarrier() 方法显式获取一个。
No, the volatile keyword and the atomicity guarantee are much too weak. You need a memory barrier to ensure that. You can get one explicitly with the Thread.MemoryBarrier() method.