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,