I was looking at some of the implementation details of Task in System.Threading.Tasks (.NET standard 2.0) and I came across this interesting piece of code:
internal volatile int m_stateFlags;
...
public bool IsCompleted
{
get
{
int stateFlags = m_stateFlags; // enable inlining of IsCompletedMethod by "cast"ing away the volatiliy
return IsCompletedMethod(stateFlags);
}
}
// Similar to IsCompleted property, but allows for the use of a cached flags value
// rather than reading the volatile m_stateFlags field.
private static bool IsCompletedMethod(int flags)
{
return (flags & TASK_STATE_COMPLETED_MASK) != 0;
}
I understand from reading C# reference guide that volatile is there to prevent compiler/runtime/hardware optimizations that would result in re-ordering of read/write to the field. Why would in this specific case specify the field as volatile just to ignore volatility when reading the field by assigning it to a variable?
It seems intended but the reasoning behind the intent is unclear to me. Also, is "cast"ing away the volatilty a common practice? In which scenarios would I want to do it vs. scenarios I absolutely want to avoid it?
Any information to help me understand this bit of code clearer is greatly appreciated.
Thanks,
volatile
is a syntax sugar of Volatile.Read
and Volatile.Write
. It ensures that any CPUs will see the same data at the same time.
So it makes only one read of the volatile variable. Then this may be used multiple times in property, method (losing the volatile nature). So it looks like it takes a snapshot of the variable and do several computations on its value.
internal volatile int m_stateFlags;
public bool IsCompleted
{
get
{
int stateFlags = m_stateFlags;
return IsCompletedMethod(stateFlags);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With