为什么不在System.Double和System.Long上挥发?

一个像我这样的问题已经被问到 ,但我的情况有点不一样。 问题是,“为什么在C#typesSystem.DoubleSystem.Int64等中不允许使用volatile关键字?

乍一看,我回答了我的同事,“在32位机器上,这些types至less需要两个滴答才能进入处理器,而.Net框架的目的是抽象出处理器的具体细节。 “ 他回应说:“如果因为处理器特定的问题阻止你使用某个function,那么它就不是抽象的东西!”

他暗示着一个处理器特定的细节不应该显示给一个使用像程序员那样“抽象”细节的框架的人。 所以,框架(或者C#)应该把这些东西抽象出来,并且为System.Double等提供相同的保证(无论是信号量,内存屏障还是其他)。 我认为框架不应该增加信号量的易变性,因为程序员并不期望这样的关键字有这样的开销,因为信号量对于32位types不是必需的。 64位types的更大开销可能会令人吃惊,因此,对于.Net框架来说,更好的办法就是不允许它,并且如果开销可以接受的话,让你在更大的types上做自己的信号量。

这导致我们调查volatile关键字的全部内容。 (见本页)。 该页面在说明中指出:

在C#中,在字段上使用volatile修饰符可以保证对该字段的所有访问使用VolatileRead或VolatileWrite。

嗯….. VolatileReadVolatileWrite都支持我们的64位types! 我的问题是,

“为什么在C#types的System.DoubleSystem.Int64等中不允许使用volatile关键字?

不是你的问题的答案,但…

我敢肯定,当你声明“在字段上使用volatile修饰符保证对该字段的所有访问使用VolatileRead或VolatileWrite”时,你所引用的MSDN文档是不正确的。

直接读取或写入volatile字段只会生成一个半栏(读取时为获取栅栏,写入时为释放栅栏)。

VolatileReadVolatileWrite方法在内部使用MemoryBarrier ,从而生成完整的fence。

Joe Duffy对并发编程有一些了解, 这是他不得不说的波动 :

(顺便说一下,很多人想知道variables的加载和存储之间的区别,这些variables被标记为volatile,并调用Thread.VolatileRead和Thread.VolatileWrite。不同之处在于前面的API比jitter代码更强大:实现了获取/通过在右侧放出完整的栅栏来释放语义,API的调用也比较昂贵,但是至less可以让你决定每个负载和存储都需要MM的保证。

他暗示了一个处理器特定的细节不应该显示给一个使用“抽象”这样的细节的人,而不是像程序员那样的细节。

如果你正在使用低locking技术,如易失性字段,显式内存障碍等,那么你完全处于处理器特定细节的世界。 为了编写使用低锁技术的正确的,可移植的,强大的程序,您需要深入理解处理器是什么,并且不允许重sorting,一致性等等。

这个特性的意义在于:“我放弃了单线程编程所保证的方便抽象,并且通过对我的处理器有深入的实现特定的知识来获得性能上的提升”。 当你开始使用低锁技术,而不是更多的抽象时,你应该期望更less的 抽象

可能是因为某种原因,你会“倒在金属上” 你付出的代价是不得不处理上述金属的怪癖。

是。 原因是你甚至无法在一个操作中读取doublelong 。 我同意这是一个糟糕的抽象。 我有一种感觉,那就是primefaces读取需要努力,编译器太聪明了。 所以他们让你select最好的解决scheme: lockInterlocked

有趣的是,他们实际上可以使用MMX寄存器在32位上自动读取。 这是Java JIT编译器所做的。 而且他们可以在64位机器上自动读取。 所以我认为这是devise上的严重缺陷。

这是遗产的简单解释。 如果您阅读本文 – http://msdn.microsoft.com/en-au/magazine/cc163715.aspx ,您会发现.NET Framework 1.x运行时的唯一实现是在x86机器上,所以它这对于微软来说是针对x86内存模型来实现的。 后来加了x64和IA64。 所以基本内存模型一直是x86的一个。

它可以用于x86吗? 我实际上不确定它是否可以完全实现 – 从本地代码返回的double的ref可以alignment到4个字节而不是8个。在这种情况下,所有对primefaces读取/写入的保证不再成立。