Thursday, 7 July 2016

Why make a bool volatile when multithreading in C#?



I understand the volatile keyword in C++ fairly well. But in C#, it appears to take a different meaning, more so related to multi-threading. I thought bool operations were atomic, and I thought that if the operation were atomic, you wouldn't have threading concerns. What am I missing?



https://msdn.microsoft.com/en-us/library/x13ttww7.aspx


Answer



The volatile keyword in C# is all about reading/writing reordering, so it is something quite esoteric.



http://www.albahari.com/threading/part4.aspx#_Memory_Barriers_and_Volatility




(that I consider to be one of the "bibles" about threading) writes:




The volatile keyword instructs the compiler to generate an acquire-fence on every read from that field, and a release-fence on every write to that field. An acquire-fence prevents other reads/writes from being moved before the fence; a release-fence prevents other reads/writes from being moved after the fence. These “half-fences” are faster than full fences because they give the runtime and hardware more scope for optimization.




It is something quite unreadable :-)



Now... What it doesn't mean:





  • It doesn't mean that a value will be read now/will be written now



it simply means that if you read something from a volatile variable, everything else that has been read/written before this "special" read won't be moved after this "special" read. So it creates a barrier. So paradoxically, by reading from a volatile variable, you guarantee that all the writes you have done to any other variable (volatile or not) at the point of the reading will be done.



A volatile write is something probably more important, and is something that is in part guaranteed by the Intel CPU, and something that wasn't guaranteed by the first version of Java: no write reordering. The problem was:



object myrefthatissharedwithotherthreads = new MyClass(5);



where



class MyClass
{
public int Value;
MyClass(int value)
{
Value = value;
}

}


Now... that expression can be imagined to be:



var temp = new MyClass();
temp.Value = 5;
myrefthatissharedwithotherthreads = temp;



where temp is something generated by the compiler that you can't see.



If the writes can be reordered, you could have:



var temp = new MyClass();
myrefthatissharedwithotherthreads = temp;
temp.Value = 5;


and another thread could see a partially initialized MyClass, because the value of myrefthatissharedwithotherthreads is readable before the class MyClass has finished initializing.



No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...