多线程编程中的一个容易忽视的地方

 

前几天一直在查一个bug,在debug下程序在初始化的时候没有问题,release下程序在初始化的时候陷入了死循环,且挂载在vs上release又不会死循环,查了好久,昨天终于查到了为什么,这里暂时不提我自己做的项目,下面我写一个demo来说明这个问题:

程序如下:

 1 class Program
 2     {
 3         private static bool s_stop = false;
 4         static void Main(string[] args)
 5         {
 6             Console.WriteLine("Mian:letting worker run for 5 seconds");
 7             Thread t = new Thread(Worker);
 8             t.Start();
 9             Thread.Sleep(5000);
10             s_stop = true;
11             Console.WriteLine("Main:waiting for worker to stop");
12             t.Join();
13         }
14 
15         private static void Worker(object o)
16         {
17             Int32 x = 0;
18             while (!s_stop) x++;
19             Console.WriteLine("Worker:stopped when x={0}", x);
20         }
21     }

程序的目的是先让一个工作线程工作,5s后,给变量s_stop赋值,让线程的方法结束循环,程序最终会退出。

目的是好的,但是这个程序有个隐患,在debug下是没有问题的,挂调试器也是没有问题的,就是release模式下有问题,程序一直会陷入死循环。

为什么呢?

编译器会优化我们的代码,s_stop在主线程和工作线程中都要访问,这就会涉及到了数据共享问题,当编译器看到Worker方法的时候,发现里面的s_stop不会改变

,且这个值是false的,那么就把后面的代码都给优化了,因为whie(true)了。

 

这种错误,我们可能在编程过程中很难发现,也很难碰到,但是一旦碰到就是灾难。

我的项目中初始化的时候是这样子的:

console.Run();

while(!console.IsBusy){}

因为console.Run是一个线程,while()又是一个线程,但是一开始IsBusy是false的,所以在编译器优化的时候while就变成了死循环了。

 

最好的作法就是在变量前面加上Volatile关键字就可以了

 

https://files.cnblogs.com/files/monkeyZhong/TestVolatile.zip

 

posted @ 2015-11-17 09:51  MonkeyZhong  阅读(280)  评论(0编辑  收藏  举报