为什么以下C#多线程代码虽然在调试器中没有输出零?

时间:2011-03-23 22:52:28

标签: c# multithreading

class Program
{
    private static volatile int value;

    public static void Increment()
    {
        for (int i =0; i <100000; i++)
        {
            value++;
        }
    }

    public static void Decrement()
    {
        for (int j =0 ; j < 100000; j++)
        {
            value--;
        }
    }

    public static void ThreadTest()
    {
        value = 0;

        var incrementThread = new Thread(Increment);

        var decrementThread = new Thread(Decrement);

        incrementThread.Start();

        decrementThread.Start();

        incrementThread.Join();

        decrementThread.Join();

        Console.WriteLine("Value of value {0}", value);
    }

    static void Main(string[] args)
    {
        ThreadTest();
    }
}

2 个答案:

答案 0 :(得分:17)

因为它不应该...... ++和 - 不是原子操作(不像Interlocked.XXXX opreations - Interlocked.Increment)。

如果你写下++和 - 的每一步,并看看两者如何通过不同的线程混合,你会明白为什么:

增量

1: load value to temp
2: add temp, 1
3: store temp to value

递减

4: load value to temp2
5: substruct temp2, 1
6: store temp2 to value

因此,如果订单是1,2,3,4,5,6,则得到值= 0;但如果订单是1,2,4,5,6,3,则得到值= 1.

答案 1 :(得分:1)

只是试图让事情更简单......我也在当天回击了这个问题:D

易失性确保您读取最新值,并且当您编写所有线程时看到该新值(这是易失性操作的用途),但它不能确保读取和写入之间,其他线程不是要修改价值。另一方面,Interlocked(提供原子操作)确实可以确保它。

当例如线程或线程读取和其他修改时,易失性操作是好的。例如,如果你的类中有一个volatile Boolean _disposed标志,那么如果一个线程处理它,它会被标记为立即为所有线程处理。