日期:2014-05-17  浏览次数:20884 次

|ZYCWPF| 为什么我在多线程中不设置volatile,而不会出现死循环呢?
http://stackoverflow.com/questions/133270/illustrating-usage-of-the-volatile-keyword-in-c-sharp/1284007
这个贴子说程序出现列循环了,说解决问题是加volatile,但我照做后,为什么我的不会出现
以下是代码

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace ThreadVolatileTest
{
    class Program
    {
        int foo;
        static void Main(string[] args)
        {
            var test = new Program();

            new Thread(delegate() { Thread.Sleep(500); test.foo = 255; }).Start();

            while (test.foo != 255)
            {
                Console.WriteLine("OK");
            }
        }
    }
}

因为我看了volatile这个的用法后,感觉和用Static没有什么差别
后发贴:今天看多线程的,但是对volatile这个关键字不理解,怎么感觉用static不是也是一样的效果吗
然后根据大牛们说的话,我理解为,难道我以前用的static 来做多线程的共享对像,得用volatile来?
然后我根据给出的测试示例,并没有测试出死循环的结果啊?
已编译为Release了

谢谢
------最佳解决方案--------------------
其实这个例子是要演示不用volatile会产生错误优化结果的情况,可以看到由于编译器越来越聪明,所以要演示出这种错误并不容易。
搞死编译器不是目的,就是说多数情况下,在编码的过程中没有必要刻意去考虑某个成员变量是否要声明为volatile,可以让编译器自己去判断,如果测试发现错误了,再加上volatile不迟。
------其他解决方案--------------------
你看看编译优化有没有打开:

再不行的话你用Reflecotr看看编译后的dll的代码,是不是循环中的条件判断已经被优化掉了。
------其他解决方案--------------------
那我可不可以这样理解,,我就当我不知道这个volatile关键字
因为昨天看多线程的时候有这个关键字,我感觉和我以前用static没有区别
所以才会问这两个问题的
谢谢
------其他解决方案--------------------
不能这样说,应该要知道,否则遇到我们讨论的例子中的这种情况,你就没法分析原因了。

那你现在试出来死循环的情况了吗?要不然你把编译后的dll上传一份来看看?
------其他解决方案--------------------
http://pan.baidu.com/share/link?shareid=128753&uk=4212471801
这个是当前这个示例的源码
还有那个关闭记事本,还能得到数量1的代码

我刚试了,我在第37次的时候,记事本那个得到了“1”
------其他解决方案--------------------
你的程序和stackoverflow上的例子是不同的。它的是这样的:
while (test.foo != 255);
Console.WriteLine("OK");
可见只有像上面这样写,编译器才会把它优化成while(true);
而你这样写:
while (test.foo != 255)
{
         Console.WriteLine("OK");
}
则不管foo是不是volatile,编译器都不会去优化。

------其他解决方案--------------------
我也试了50多次没出现错误。
是不是你测试的时候按键按得太快,导致在notepad中输入了字符,退出的时候有提示“是否保存”?

还有你给我的版本没有加WaitForExit等待,理论上是可能在退出前就执行了GetProcessesByName,不过我试了50几次也都是正常的提示0
------其他解决方案--------------------
我又试了下终于发现了确实会出现1,估计是process先退出,然后再从进程列表中删除。
我加上Thread.Sleep(1);延迟1毫秒,然后又试了50多次,就没有发现问题了。