为什么使用volatile产生不同的结果?

时间:2012-12-11 06:47:19

标签: c#

    private const int Total = 500000;
    private static volatile int _count = 0;

    private static void Main()
    {
        Task task = Task.Factory.StartNew(Decrement);
        for (int i = 0; i < Total; i++)
        {
            _count++;
        }

        task.Wait();
        Console.WriteLine(_count);

        Console.ReadLine();
    }

    private static void Decrement()
    {
        for (int i = 0; i < Total; i++)
        {
            _count--;
        }
    }

有时结果为0,有时结果为-xxxxxx。我不知道为什么。任何人都可以解释它并告诉我正确的用法。

2 个答案:

答案 0 :(得分:5)

volatile保证不重新排序操作并禁用缓存优化,但不保证线程安全 - 因此您可以获得从0到-Total的任何结果(如果每对--++已正确混合)。我已经在回答Why the following C# multi-threaded code does not output zero though it does in debugger?时介绍了“preper mixing”。

volatile在您希望其他人修改值时非常有用,因此您的代码始终会读取合理的近期值,这也是一致的(即对于++,您不会得到int高的值0xffff的一部分和(0xffff + 1)的低部分 - 你将得到一个或另一个)因为volatile只适用于原子写入的类型。

如果您想在2个主题中修改计数器 - 请使用Interlocked.Increment / Interlocked.Decrement

答案 1 :(得分:3)

volatile不保证线程安全,因为在Alexei Levenkov的回答中说明了这一点。您可以使用System.Threading.Interlocked

之后你的例子将会是这样的:

    private const int Total = 500000;
    private static volatile int _count = 0;

    private static void Main()
    {
        Task task = Task.Factory.StartNew(Decrement);
        for (int i = 0; i < Total; i++)
        {
            System.Threading.Interlocked.Increment(ref _count);
        }

        task.Wait();
        Console.WriteLine(_count);

        Console.ReadLine();
    }

    private static void Decrement()
    {
        for (int i = 0; i < Total; i++)
        {
            System.Threading.Interlocked.Decrement(ref _count);
        }
    }