Why the following C# multi-threaded code does not output zero though it does in debugger?
class Program
{
private static volatile int value;
public static void Increment()
{
for (int i =0; i <100000; i++)
{
value++;
}
}
public static void Decrement()
{
开发者_如何学JAVA 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();
}
}
Because it is not supposed to... ++ and -- are not atomic operations (unlike Interlocked.XXXX opreations - Interlocked.Increment).
If you write down each step of ++ and -- and see how both can be intermixed by different threads you'll see why:
increment
1: load value to temp
2: add temp, 1
3: store temp to value
decrement
4: load value to temp2
5: substruct temp2, 1
6: store temp2 to value
So if order is 1,2,3,4,5,6 you get value = 0; but if order is 1,2,4,5,6,3 you get value = 1.
Only trying to make the things simpler... I fought this issue back in the day as well :D
Volatile ensure you read the latest value, and when you write all threads see that new value (and that is what volatile operations are for), but it doesn't ensure that between the read and the write, other thread is not going to modify the value. In the other hand, Interlocked (that provides atomic operations) does ensure it.
Volatile operations are good, when for example a thread or threads read and other modify. For example if you have a volatile Boolean _disposed
flag in your class, so if one thread dispose it, it's marked as disposed for all threads straight away.
精彩评论