"Loads are not reorderd with other loads" is a FACT!! 续:不要指望 volatile

上一篇随笔中提到了volatile,实际上由于上一篇中提到的问题,volatile已经越来越远离其应有的含义了。在说这个问题之前,我们又要提.NET的内存模型问题(以下简称MM),我不指望在这里长篇大论的说其内存模型是如何的。简单的说就是以下的几句话:

 

第一、load与store之间的数据依赖关系不会被改变

第二、所有的store操作都有release语义,所有的volatile的load都有acquire语义,

第三、所有的load与store都不能跨越memory barrier(full fence,全内存栅栏)

第四、load和store仅仅在紧邻的对于相同位置的load和store存在时才可能被移除。

 

所谓acquire与release是怎么一回事,这个~acquire可以理解为,没有其他的操作(对内存的)可以将自己执行的顺序调整到它之前;相反的,release可以理解为,没有其他的操作可以将自己的执行调整到它之后。但是请注意!acquire和release已经是半个内存栅障了!他应该对CPU的可见性产生影响。好,我们先不提这个,假设MS目前的x86, x64上的.NET的MM是完美实现的。看看MSDN对volatile的解释是什么:

 

第一句:

The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time.

这句实际上没有说任何的实际内容。

第二句:

Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread.

这句指出了volatile的一个作用--防止编译器优化你的代码,虽然提到了编译器对于volatile不再认为是单线程访问的,但是仅仅是assume,这并不能解决任何问题。

第三句:

This ensures that the most up-to-date value is present in the field at all times.

这是什么?这完全说明了我们上面所说的volatile的作用:volatile的load具有release语义!

第四句:

The volatile modifier is usually used for a field that is accessed by multiple threads without using the lock statement to serialize access.

实际上他想说,如果你向volatile中执行了store,那么你在load中(即使在另一个线程)也会获得most up to date的值。这样我们就不必使用lock再引入同步或者memory fence了。

 

好了,按照上面的解释,如果.NET的MM是完美实现了的,OK,全部说得过去!但是请看上一篇随笔,不是的!volatile根本不能保证load是acquire的!也就是,Microsoft的.NET Framework在x86与Intel 64的平台下的实现是有漏洞的(这跟Intel一点没有关系,不要误会,是.NET的MM的问题)!因此,不要指望MSDN的解释了。在你书写Multi-thread Application的时候,还是多留一个心眼吧。

 

如果要修补这个漏洞,那么volatile的load需要半个memory fence,但是请看看x86,x64的文档,你就知道,这里不得不要一个full fence。也就是,volatile的load是完全不会被reorder的,这合适么?我不知道,我不知道真正的Java MM的官方解释在哪里,但是目前至少有文档表明,Java的volatile是一个full fence。

 

最后,我想说明一点。大部分战友们,大部分时间内,根本不用为这个操心劳神。Please don't be panic:-)

posted @ 2008-07-19 19:55  TW-刘夏  阅读(3628)  评论(3编辑  收藏