简体   繁体   中英

Why does using volatile produce a different result?

    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--;
        }
    }

Sometimes the result is 0,sometimes the result is -xxxxxx. I don't know why. Can anybody explain it and tell me the correct usage.

volatile guarantees no reordering of operations and disable caching optimizations, but does not guarantees thread safety - so you can get any result from 0 to -Total (if every pair of -- and ++ are properly mixed). I've covered "preper mixing" in answer to Why the following C# multi-threaded code does not output zero though it does in debugger? .

volatile is useful when you expect someone else to modify value so your code always reads reasonably recent value, which also will be consistent (ie for ++ you'll not get int consisting of high part of 0xffff and low part of (0xffff+1) - you'll get either one or another) since volatile is only applicable to types that are writen atomically.

If you want to modify counter in 2 threads - use Interlocked.Increment / Interlocked.Decrement .

volatile does not guarantee thread-safety as it was stated in Alexei Levenkov's answer. You can use System.Threading.Interlocked .

Your example will look like something like this after that:

    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);
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM