为什么C#volatile不保护写 – 读重新排序?

根据这本在线书籍 ,C#中的volatile关键字不能防止重新排序Write操作,然后是Read操作。 它给出了这个例子,其中ab都可以最终设置为0 ,尽管xyvolatile

 class IfYouThinkYouUnderstandVolatile { volatile int x, y; void Test1() // Executed on one thread { x = 1; // Volatile write (release-fence) int a = y; // Volatile read (acquire-fence) ... } void Test2() // Executed on another thread { y = 1; // Volatile write (release-fence) int b = x; // Volatile read (acquire-fence) ... } } 

这似乎符合规范在10.5.3中所说的内容:

读取volatile字段称为volatile读取。 易失性读取具有“获取语义”; 也就是说,保证在指令序列之后的任何内存引用之前发生。

写入易失性字段称为易失性写入。 易失性写入具有“释放语义”; 也就是说,保证在指令序列中的写指令之前的任何存储器引用之后发生。

这是什么原因? 是否有一个用例,我们不介意重写读写操作?

Volatile不保证读取和写入不会重新排序,它只保证读取获得最新的值(非缓存)。

http://msdn.microsoft.com/en-us/library/x13ttww7%28v=vs.71%29.aspx

系统始终在请求的位置读取易失性对象的当前值,即使前一条指令要求来自同一对象的值也是如此。 此外,在分配时立即写入对象的值。

volatile修饰符通常用于多个线程访问的字段,而不使用lock语句来序列化访问。 使用volatile修饰符可确保一个线程检索另一个线程写入的最新值。

只要有多个相关操作,就需要使用其他一些同步机制。 通常使用lock ,这是最容易的,只会在滥用或极端情况下造成性能瓶颈。

也许来不及回答……但我环顾四周,看到了这一点。 Volatile-read实际上是对类似于以下方法的调用:

 public static int VolatileRead(ref int address) { int num = address; Thread.MemoryBarrier(); return num; } 

而Volatile-write就是这样的:

 public static int VolatileWrite(ref int address, int value) { Thread.MemoryBarrier(); adrdress = value; } 

指令MemoryBarrier(); 是防止重新排序的人。 MemoryBarrier(); 确保之前的intructions在之后的intructions之前执行。 当大众然后VR,你将有:

 Thread.MemoryBarrier(); adrdress = value; //this line may be reordered with the one bellow int num = address;//this line may be reordered with the one above Thread.MemoryBarrier(); return num; 

在x86 / x64 arch上,使用volatile read重新排序防止volatile write将非常昂贵。 那是因为写优化称为store buffers 。 Java采用这种方式,Java中的易失性写入实际上是CPU指令级别的完全内存屏障。