I have a few simple (hopefully) questions that I have been unable to find answers for -
Say I have objects a, b that are accessible to multiple threads.
Interlocked.Exchange(ref a, b)
the variable passed to
Exchange (or any volatile variable passed to any method) does not retain "volatility" when passed... There's actually no need for it to be
volatile (for the duration of the method call) because the only thing that
volatile does is to make sure that the compiler(s) do not optimize use of the variable (which generally means optimizing writes into registers so the value can only be "seen" by a single processor). On processors other than x86/x64, this sometimes means instructions that guarantee acquire or release semantics. .NET doesn't use registers for argument passing, so volatile couldn't affect "volatility" of the arguments passed. It has to always get the latest value from memory due to visibility guarantees of the memory model
RE question 2: the quote is "sort of" true, depending on the declaration of a field, there are visibility guarantees w.r.t. fields; but without "volatile" field access can be optimized into a register in certain phases of use, potentially hiding certain writes from other processors.
Interlocked exchanges make operations that were not atomic appear atomic. Exchange by nature is similar to:
var x = someVariable; someVariable = y;
This cannot be atomic regardless of the type of
Exchange makes this operation atomic. This is also atomic with non-atomic types like
long (in 32-bit), etc.
Part of what
Exchange does to make this atomic is to use memory fences--which make writes visible and not re-ordered with reads of the same memory address in the sequence of instructions after the memory fence.
Why would you use
Exchange if you don't care about the previous value of 'a'? If you don't care about an actual "exchange", then
VolatileWrite seems more appropriate.
Alternatively, if "exchange" is not needed, you could write thread-safe code to model "A=B" as follows:
Interlocked is partially modelled around compare-and-swap (CAS) instructions in some processors. These instructions allow you to do these two operations in one instruction (making it atomic). Without things like
Interlocked it could be difficult for a compiler to infer that one of these CAS instruction should be used . In addition,
Interlocked provides atomic usage on processors that don't support these CAS instructions (and other potentially non-atomic instructions like inc and dec--that may not be available on all processors)