Here is my take on the subject and to attempt to provide a quasi-complete list in one answer. If I run across any others I will edit my answer from time to time.
Mechanisms that are generally agreed upon to cause implicit barriers:
- All
Monitor
class methods including the C# keywordlock
- All
Interlocked
class methods. - All
Volatile
class methods (.NET 4.5+). - Most
SpinLock
methods includingEnter
andExit
. Thread.Join
Thread.VolatileRead
andThread.VolatileWrite
Thread.MemoryBarrier
- The
volatile
keyword. - Anything that starts a thread or causes a delegate to execute on another thread including
QueueUserWorkItem
,Task.Factory.StartNew
,Thread.Start
, compiler suppliedBeginInvoke
methods, etc. - Using a signaling mechanism such as
ManualResetEvent
,AutoResetEvent
,CountdownEvent
,Semaphore
,Barrier
, etc. - Using marshaling operations such as
Control.Invoke
,Dispatcher.Invoke
,SynchronizationContext.Post
, etc.
Mechanisms that are speculated (but not known for certain) to cause implicit barriers:
Thread.Sleep
(proposed by myself and possibly others due to the fact that code which exhibits a memory barrier problem can be fixed with this method)Thread.Yield
Thread.SpinWait
Lazy<T>
depending on whichLazyThreadSafetyMode
is specified
Other notable mentions:
- Default add and remove handlers for events in C# since they use
lock
orInterlocked.CompareExchange
. - x86 stores have release fence semantics
- Microsoft’s implemenation of the CLI has release fence semantics on writes despite the fact that the ECMA specification does not mandate it.
MarshalByRefObject
seems to suppress certain optimizations in subclasses which may make it appear as if an implicit memory barrier were present. Thanks to Hans Passant for discovering this and bringing it to my attention.1
1This explains why BackgroundWorker
works correctly without having volatile
on the underlying field for the CancellationPending
property.