今天在MSDN的Interlocked.Increment 方法 (Int32) 的示例中看到两个变量经过“相同的”运算后,最后结果却不同,貌似理由是线程安全什么的 ,不太懂。现在把例子的代码贴出来了,请高手分析一下 为什么SafeInstanceCount和UnsafeInstanceCount两个变量的值不同??!! 我怎么感觉肯定相同呢!!唉 越来越发现自己编程学的好差!
例子如下:下面的代码示例说明增加和减少整数值的线程安全方式。SafeInstanceCount 始终为 0。但是 UnsafeInstanceCount 不一定为 0,因为在增加和减少计数之间会出现争用条件。此效果在多处理器计算机上尤其明显。using System;
using System.Threading;class Test
{
static void Main()
{
Thread thread1 = new Thread(new ThreadStart(ThreadMethod));
Thread thread2 = new Thread(new ThreadStart(ThreadMethod));
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join(); // Have the garbage collector run the finalizer for each
// instance of CountClass and wait for it to finish.
GC.Collect();
GC.WaitForPendingFinalizers(); Console.WriteLine("UnsafeInstanceCount: {0}" +
"\nSafeCountInstances: {1}",
CountClass.UnsafeInstanceCount.ToString(),
CountClass.SafeInstanceCount.ToString());
} static void ThreadMethod()
{
CountClass cClass; // Create 100,000 instances of CountClass.
for(int i = 0; i < 100000; i++)
{
cClass = new CountClass();
}
}
}class CountClass
{
static int unsafeInstanceCount = 0;
static int safeInstanceCount = 0; static public int UnsafeInstanceCount
{
get {return unsafeInstanceCount;}
} static public int SafeInstanceCount
{
get {return safeInstanceCount;}
} public CountClass()
{
unsafeInstanceCount++;
Interlocked.Increment(ref safeInstanceCount);
} ~CountClass()
{
unsafeInstanceCount--;
Interlocked.Decrement(ref safeInstanceCount);
}
}
例子如下:下面的代码示例说明增加和减少整数值的线程安全方式。SafeInstanceCount 始终为 0。但是 UnsafeInstanceCount 不一定为 0,因为在增加和减少计数之间会出现争用条件。此效果在多处理器计算机上尤其明显。using System;
using System.Threading;class Test
{
static void Main()
{
Thread thread1 = new Thread(new ThreadStart(ThreadMethod));
Thread thread2 = new Thread(new ThreadStart(ThreadMethod));
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join(); // Have the garbage collector run the finalizer for each
// instance of CountClass and wait for it to finish.
GC.Collect();
GC.WaitForPendingFinalizers(); Console.WriteLine("UnsafeInstanceCount: {0}" +
"\nSafeCountInstances: {1}",
CountClass.UnsafeInstanceCount.ToString(),
CountClass.SafeInstanceCount.ToString());
} static void ThreadMethod()
{
CountClass cClass; // Create 100,000 instances of CountClass.
for(int i = 0; i < 100000; i++)
{
cClass = new CountClass();
}
}
}class CountClass
{
static int unsafeInstanceCount = 0;
static int safeInstanceCount = 0; static public int UnsafeInstanceCount
{
get {return unsafeInstanceCount;}
} static public int SafeInstanceCount
{
get {return safeInstanceCount;}
} public CountClass()
{
unsafeInstanceCount++;
Interlocked.Increment(ref safeInstanceCount);
} ~CountClass()
{
unsafeInstanceCount--;
Interlocked.Decrement(ref safeInstanceCount);
}
}
a++等同于
a = a+1;
这里面需要先把a的值取出来,然后加1,然后再把值赋给a
对于CPU来说这是两个过程,把a的值读出来,放到寄存器,累加,再把寄存器里的值读出来,赋值给a。
如果这个过程被打断会发生什么呢,以下的两个a++在不同线程中
a= 0;
a++;
a++;
第一个a++进行到给a赋值之前被打断,此时寄存器里的值是1。然后执行第二个a++。第二个a++执行之后a的值是1,然后切换回第一个给a赋值的阶段,相当于把之前算好的1赋值给a,所以两次a++之后a的值竟然是1.
即使像简单的变量自增操作 a++,也不是原子的。
即这个 a++的操作有可能不是在一个时间片中执行完成的,执行a++的操作可能会被其它线程抢占。
而在此之间它没有预见到其它线程可能已经修改了a本身的值Interlocked.Increment(ref safeInstanceCount)操作,或lock就是为了解决这个问题的。
让该操作原子完成,不被其它线程抢占。
即使像简单的变量自增操作 a++,也不是原子的。
即这个 a++的操作有可能不是在一个时间片中执行完成的,执行a++的操作可能会被其它线程抢占。
而在此之间它没有预见到其它线程可能已经修改了a本身的值Interlocked.Increment(ref safeInstanceCount)操作,或lock就是为了解决这个问题的。
让该操作原子完成,不被其它线程抢占。
谢谢!!!看了你们的指点 貌似我明白了些 呼呼~~