Why does the use of volatile products lead to 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 do not know why. Can someone explain this and tell me the correct use.

+6
source share
2 answers

volatile does not guarantee reordering of operations and disables cache optimization, but it does not guarantee thread safety - therefore, you can get any result from 0 to -Total (if every pair -- and ++ mixes correctly). I examined "pre-mixing" in response to Why the following multi-threaded C # code does not output zero, although it works in the debugger? .

volatile is useful when you expect someone else to change the value, so your code always reads a reasonably recent value that will also be consistent (i.e. for ++ you won't get an int consisting of the high part 0xffff and the low part ( 0xffff + 1) - you get one or the other), since volatile applies only to types that are atomically written.

If you want to change the counter in 2 threads, use Interlocked.Increment / Interlocked.Decrement .

+5
source

volatile does not guarantee thread safety, as was said in Alexey Levenkovโ€™s answer. You can use System.Threading.Interlocked .

After that, your example will look something like this:

  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); } } 
+3
source

All Articles