发表评论
@Jeffrey Zhao
多线程的文章,大家都不太爱看吧。
尤其这篇还要涉及到CPU架构以及内存交互。
在并发情况下
用了这东西反而更麻烦
尤其是大多数人都不理解它是啥用的
推荐只用在高实时响应且场景较简单的情况下
简单的说就是只用在元类型数据的单一读写
其他的情况会搞得很复杂
但我的原则是
宁愿增加锁的开销,也绝对不用 volatile
@Angel Lucifer
我觉得可能是工作中涉及到这方面的人不多,这也不是当下关注的重点。:)
@Zealic
嗯,其实volatile和lock还是有区别的,而且我觉得解决的问题其实并没有太多接近的地方,这点从文章里“两个准则”可以看出来……
@Jeffrey Zhao
“两个准则”其实和我所说的“元类型数据的单一读写”意思相差不多,不过我的要求更严格一些
多线程/并发 还是严格控制在自己手里比较好,否则代码一旦膨胀起来,就会陷入 Debug 地狱。
不能太依赖编译器!
volatile有很多益用的场合,我在很多工程里都用到了这个关键字,其实在msdn说的很清楚:
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. This ensures that the most up-to-date value is present in thed field at all times.
它可以高效的提供在多线程环境下,对一个field的访问的状态同步。
在demo中提到了在复合对象的集合上应用可能会导致一些副作用。事实上这是因为它只能原子性的提供简单对象的同步。
对我这样专业基础不是太好的人来说,例子就是一切。。。
如果楼主能够通过代码表现出用和不用volatile的区别那就太好。
顺便问一下cs规范里面关于volatile的那个例子:
~~~~~~~~cs语言规范里的原文开始~~~~~~~~~~~~~
using System;
using System.Threading;
class Test
{
public static int result;
public static volatile bool finished;
static void Thread2() {
result = 143;
finished = true;
}
static void Main() {
finished = false;
// Run Thread2() in a new thread
new Thread(new ThreadStart(Thread2)).Start();
// Wait for Thread2 to signal that it has a result by setting
// finished to true.
for (;;) {
if (finished) {
Console.WriteLine("result = {0}", result);
return;
}
}
}
}
产生下列输出:
result = 143
在本示例中,方法 Main 启动一个新线程,该线程运行方法 Thread2。该方法将一个值存储在叫做 result 的非可变字段中,然后将 true 存储在可变字段 finished 中。主线程等待字段 finished 被设置为 true,然后读取字段 result。由于 finished 已被声明为 volatile,主线程从字段 result 读取的值一定是 143。如果字段 finished 未被声明为 volatile,则存储 finished 之后,主线程可看到存储 result,因此主线程从字段 result 读取值 0。将 finished 声明为 volatile 字段可以防止这种不一致性。
~~~~~~~~cs语言规范里的原文结束~~~~~~~~~~~~
我测试了大概100遍把volatile去掉也没有输出过0,都是143。volatile难道只是为了避免偶尔出现的优化?(也就是没有volatile并不必然作出优化)
@John Rambo
你需要在CPU不共享缓存的系统上测试。至少要QUAD-CORE或两个以上的独立CPU
@John Rambo
我猜你用来测试的程序跑在x86/x64架构的机器上。x86架构的CPU会维持高速缓存一致性,x64则向后兼容x86,所以如果在其上运行测试程序,不会观察到这个问题,也就是说程序要么不显示任何东西,要么显示143。
在CLR 2.0 Memory Model中仔细的讲解了x86架构的行为。
@Zealic
volatile的确是个令人讨厌的东西,而且应用场景也非常有限。
接下来我会探讨关于原子操作和无锁编程,这个就有点意思了。
@lbq1221119
Thanks,:-)
@Q.Lee.lulu
war3虽然玩过,但是玩的不咋地。这个名字在war3出来N久之前,就一直再用了,我是比较欣赏Lucifer的,嘿嘿。
@Angel Lucifer
谢谢你的讲解。我确实是在x86上跑的,pentium D 1.6g。这些东西实在是太奇妙了。
volatile对于多线程程序几乎可以说没有作用,你仅仅在阻止编译器优化你的代码并且在一些情况下,更改load的的语义。不要理会MSDN上的说明。MSDN对于volatile的说明包含太多的误导成分。
实际上对于.NET,volatile很简单,任何对于volatile的load均有acquire语义,任何对于(不关事volatile还是非volatile的)store均有release语义。并且,不论是load acq还是 store rel都是针对当前的processor而言的,并不保证对于其他 processor的可见性。因此说volatile对于可见性有帮助也是没有设么原因的。