一、volatile的局限
上一节,我们简要的分析了volatile对易失性的支持,对于某些字段可能被多线程共享时,我们往往要考虑这些字段的可见性,以及考虑CPU和编译器对代码顺序进行优化(尽管编译器和CPU在实际中很少这样做)带来的不可预知的影响,因此C#提供了volatile关键字,它告诉编译器确保对易失字段的所有访问都是以易失读取或者易失写入的方式执行,并且告诉C#和JIT编译器不将字段缓存到CPU的寄存器中.
Volatile,虽然十分强大,事实上,很多语言中,都有volatile这个关键字,例如c/c++/java等,但volatile也有它的局限性:
1、 volatile关键字,仅可以作用于类或者结构中的字段,不能将局部变量声明为volatile
2、 volatile只能修饰属于硬件层面读写的原子操作的类型,例如byte/int/uint/char等,而不能修饰long这种超出一条指令读取操作的类型(当然这里主要是针对CPU位数而言)
3、Volatile 关键字不支持引用传递的参数。
因此,C#又提供了一组静态读写方法,Thread.VolatileRead和Thread.VolatileWrite,在讲述这两个方法之前,我们有必要了解另一个方法 Thread.MemoryBarrier。
二、内存栅栏
Thread.MemoryBarrier方法执行一个内存栅栏操作,MSDN对这个方法的解释如下:
“按如下方式同步内存访问:执行当前线程的处理器在对指令重新排序时,不能采用先执行 MemoryBarrier 调用之后的内存访问,再执行 MemoryBarrier 调用之前的内存访问的方式”
这是MSDN的官方解释,但是我觉得这个解释很不好,很容易让人觉得,它只是阻止处理对调用MemoryBarrier前后内存操作指令进行重排,我个人第一次看这个解释的时候,只注意MSDN强调的是顺序性。但其实这个方法的作用除了阻止指令重排之外应该还有另外一作用,刷新寄存器
即我的理解是,调用MemoryBarrier有两个作用:
1、阻止编译器和CPU对调用MemoryBarrier前后的内存操作进行优化乱序
2、刷新寄存器,刷新寄存器的过程中包括两个步骤,第一步将调用MemoryBarrier方法之前,所有的缓存写入内存,第二步,清空所有缓存,或者失所有缓存失效
(这一步我要提示,这只是我的暂时理解,我没有充足的证据,这句话如果有误,非常希望指证)
总结一句话理解呢,除去顺序性的问题,当一个写入操作完成后,