I’m having some questions I’d like to clarify.
-
Volatile read ensure you read the
latest value of a variable. Does it
means that it forces to all CPU’s to
flush their cached values for that
variable? only that variable or all?
So if it will force all CPUs to
flush cached writes and get latest
version from main memory, is this a
memory barrier? -
Volatile write ensure you write a
value to the variable in main
memory. Does it means that it void
all the cached values for that
variable in all CPUs? -
Are you using a memory barrier when
you use the keyword volatile? -
Interloked performs a
read/modify/write in an atomic
operation. Does Interlocked ensure
that you are for example
incrementing the latest version of a
variable and the other CPUs will see
this change? I think so because it’s
supposed to use a memory barrier,
but I’m not sure. So could we say
that Interloked is doing a
VolatileRead/modify/VolatileWrite
atomically? -
When you use a memory barrier, does
it affect to all variables in all
CPUS, or just the surrounding ones? -
Locking is expensive because it
causes two memory barriers and a
“context switch” if the thread has
to wait, but then what is the
advantage of Interlocked? just to
avoid the “context switch”? -
What is the deal with
ReaderWriterLockSlim and
recursivity? I didn’t understans
what is the issue.
As you can see, I have a total mess in my mind right now.
Thanks in advance.
Before answering your questions I should point out that memory barriers affect more than just the CPU. There are really two memory models in play when an application runs. One is at the hardware level and the other is at the software level. As a developer you have to code for the weakest combination of the different elements from both. With the CLR and an x86 architecture this usually means the CLR is more important because the x86 architecture actually has a fairly strong memory model. In other words, the
volatilekeyword and other memory barriers mechanisms will affect how the JIT produces code as well.First, technically a volatile read does not ensure you read the latest value of a variable. All it actually means is that no other read or write can occur before the volatile one. However, the effect is that the read has to come from main memory if it is preceded by another volatile read. Second, no, a volatile read has no influence on other writes so it does not force all CPUs to flush their write cache. Third, yes a volatile operation is considered a memory barrier.
Similiar to a volatile read, a volatile write is technically about ordering. It ensures that no other read or write can occur after the volatile one. It does not mean that the write in question immediately gets committed. It only affects the CPU executing that thread. Interestingly, the x86 architecture actually treats all writes as volatile. But, the CLR does not (at least the ECMA specification). That is why you still have to use a volatile operation on writes. This is one example of coding for the weakest memory model element from both the hardware and software level.
Yes. There are two types of memory barriers. Full fences and half fences. Half fences can either guarentee acquire semantics (volatile read) or release semantics (volatile write), but not both at the same time. A full fence (via
Thread.MemoryBarrierfor example) guarentees both.Yep. And for what is worth the interlocked increment and decrement operations can be implemented with a CAS operation. In .NET you would use the
Interlocked.CompareExchangemethod in a loop until the operation succeeded. I bet theInterlocked.IncrementandInterlocked.Decrementmethods use a native CPU instruction though, but I am prepared to be wrong about that.It will affect all memory accesses, but only on the CPU executing that thread.
Yeah basically. The thread never blocks with interlocked operations.
You cannot acquire the lock twice on the same thread without first releasing it. There is more information on Joe Duffy’s blog.