你永远不应该使用 Thread.VolatileRead/Write()。这是 .NET 1.1 中的设计错误,它使用了完整的内存屏障。这在 .NET 2.0 中已得到纠正,但他们无法再修复这些方法,不得不添加由 System.Threading.Volatile 类提供的新方法。这是 jitter 知道的一个类,它用适合特定处理器类型的版本替换jit 时的方法。
可通过参考源获得的 Volatile 类的源代码中的注释讲述了这个故事(已编辑以适应):
// Methods for accessing memory with volatile semantics. These are preferred over
// Thread.VolatileRead and Thread.VolatileWrite, as these are implemented more
// efficiently.
//
// (We cannot change the implementations of Thread.VolatileRead/VolatileWrite
// without breaking code that relies on their overly-strong ordering guarantees.)
//
// The actual implementations of these methods are typically supplied by the VM at
// JIT-time, because C# does not allow us to express a volatile read/write from/to
// a byref arg. See getILIntrinsicImplementationForVolatile() in jitinterface.cpp.
是的,你很难找到它的用法示例。参考源是一个很好的指南,其中包含数兆字节的精心编写、测试和战痕累累的处理线程的 C# 代码。它使用 VolatileRead/Write 的次数:零。
坦率地说,.NET 内存模型与 CLR mm 和 C# mm 做出的相互矛盾的假设一团糟,最近才为 ARM 内核添加了新规则。volatile关键字的怪异语义对不同的架构意味着不同的事物,这就是一些证据。尽管对于内存模型较弱的处理器,您通常可以假设 C# 语言规范所说的内容是准确的。
请注意,Joe Duffy 已经放弃了所有希望,并且完全不鼓励所有使用它。一般来说,假设您可以比语言和框架提供的原语做得更好是非常不明智的。Volatile 类的 Remarks 部分说明了这一点:
一般情况下,C# lock 语句、Visual Basic SyncLock 语句和 Monitor 类提供了同步访问数据的最简单和最不容易出错的方式,而 Lazy 类提供了一种无需直接使用即可编写惰性初始化代码的简单方式双重检查锁定。