I have a small test application that executes two threads simultaneously. One increments a static long _value, the other one decrements it. I\'ve ensured with
The CLR memory model guarantees (requires) that loads/stores can't cross a fence. It's up to the CLR implementers to enforce this on real hardware, which they do. However, this is based on the advertised / understood behavior of the hardware, which can be wrong.
Cache coherence in this case does not depend on lock. If you use lock statement it ensures that your assembler commands are not mixed.
a += b is not an atomic to processor, it looks like:
And without lock it may be:
But it's not about cache coherence, it's a more high-level feature.
So, lock does not ensures that the caches are synchronized. Cache synchronization is a processor internal feature which does not depend on code. You can read about it here.
When one core writes a value to memory and then when the second core try to read that value it won't have the actual copy in its cache unless its cache entry is invalidated so a cache miss occurs. And this cache miss forces cache entry to be updated to actual value.
The lock keyword is just syntactic sugar for a pair of System.Threading.Monitor.Enter() and System.Threading.Monitor.Exit() calls. The implementations of Monitor.Enter() and Monitor.Exit() put up a memory fence which entails performing architecture appropriate cache flushing. So your other thread won't proceed until it can see the stores that results from the execution of the locked section.