6
    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.

Joshua Enfield
  • 17,642
  • 10
  • 51
  • 98
Scarface
  • 89
  • 5

2 Answers2

5

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 (i.e. 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.

Community
  • 1
  • 1
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • i see,volatile ensures that the most up-to-date value is present in the field at all times.but the thread is not execute randomly,so sometimes i get 0,sometimes i get -xxxxx.I confuse by the up-to-date just now.Am i right? – Scarface Dec 11 '12 at 07:01
  • @Scarface, turned out I've already wrote similar answer - check the edit. – Alexei Levenkov Dec 11 '12 at 07:04
3

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);
        }
    }
Leri
  • 12,367
  • 7
  • 43
  • 60