I know that the .NET memory model (on the .NET Framework; not compact/micro/silverlight/mono/xna/what-have-you) guaranteed that for certain types (most notably primitive integers and references) operations were guaranteed to be atomic.
Further, I believe that the x86/x64 test-and-set instruction (and Interlocked.CompareExchange
) actually references the global memory location, so if it succeeds another Interlocked.CompareExchange
would see the new value.
Finally, I believe that the volatile
keyword is an instruction to the compiler to propagate reads & writes ASAP and to not reorder operations concerning this variable (right?).
This leads to a few questions:
Interlocked.Read
does not have an overload for int, only for longs (which are 2 WORDs and thus are not normally read atomically). I always assumed that the .NET memory model guaranteed that the newest value would be seen when reading ints/references, however with processor caches, registers, etc. I'm starting to see this may not be possible. So is there a way to force the variable to be re-fetched?If there are two global integer variables x and y, both initialized to 0 that if I write:
x = 1;
y = 2;
That NO thread will see x = 0 and y = 2 (i.e. the writes will occur in order). Does this change if they are volatile?
Interlocked.CompareExchange
will see the updated value.x = 0
and y = 2
, and using the volatile keyword doesn't change that because the CPU is free to re-order instructions. You need a memory barrier.Summary: