C#线程系列讲座(4):同步与死锁2011-05-08虽然线程可以在一定程度上提高程序运行的效率,但也会产生一些副作用。让 我们先看看如下的代码:
class Increment
{
private int n = 0;
private int max;
public Increment(int max)
{
this.max = max;
}
public int result
{
get
{
return n;
}
set
{
n = value;
}
}
public void Inc()
{
for (int i = 0; i < max; i++)
{
n++;
}
}
}
class Program
{
public static void Main()
{
Increment inc = new Increment(10000);
Thread[] threads = new Thread[30];
for (int i = 0; i < threads.Length; i++)
{
threads[i] = new Thread(inc.Inc);
threads[i].Start();
}
for (int i = 0; i < threads.Length; i++)
{
threads[i].Join();// 等待30个线程都执行完
}
Console.WriteLine(inc.result);//输出n的值
}
}
上面的程序的基本功能是使用Increment的Inc方法为n递 增max,所不同的是,将在Main方法中启动30个线程同时执行Inc方法。在本例中 max的值是10000(通过Increment的构造方法传入)。读者可以运行一下这个程序 ,正常的结果应该是300000,但通常不会得到这个结果,一般获得的结果都比 300000小。其中的原因就是Inc方法中的n++上,虽然从表面上看,n++只是一条简 单的自增语言,但从底层分析,n++的IL代码如下:ldsfld// 获得n的初 始值,并压到方法栈中ldc.i4.1// 将1压到方法栈中add// 从方 法栈中弹出最顶端的两个值,相加,然后将结果保存在方法栈中stfld// 从当前方法栈中弹出一个值,并更新类字段n对于上面每一条IL语句是线 程安全的,但是n++这条C#语句需要上面的四步才能完成,因此,n++这条语句并 不是线程安全的。只要在执行stfld指令之前的任何一步由于其他线程获得CPU而 中断,那么就会出现所谓的“脏”数据。