读书人

关于增加和减少整数值的线程安全方式的

发布时间: 2012-05-08 22:09:41 作者: rapoo

关于增加和减少整数值的线程安全方式的困惑!!求高手解惑
今天在MSDN的Interlocked.Increment 方法 (Int32) 的示例中看到两个变量经过“相同的”运算后,最后结果却不同,貌似理由是线程安全什么的 ,不太懂。现在把例子的代码贴出来了,请高手分析一下 为什么SafeInstanceCount和UnsafeInstanceCount两个变量的值不同??!! 我怎么感觉肯定相同呢!!唉 越来越发现自己编程学的好差!
例子如下:


C# code
下面的代码示例说明增加和减少整数值的线程安全方式。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.

[解决办法]
首先你一定得知道这个概念,在c#中绝大多数的操作都不是原子的。
即使像简单的变量自增操作 a++,也不是原子的。
即这个 a++的操作有可能不是在一个时间片中执行完成的,执行a++的操作可能会被其它线程抢占。
而在此之间它没有预见到其它线程可能已经修改了a本身的值

Interlocked.Increment(ref safeInstanceCount)操作,或lock就是为了解决这个问题的。
让该操作原子完成,不被其它线程抢占。

读书人网 >C#

热点推荐