Memory barrier generators
c#, memory-barriers
Solution
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# keyword `lock`
- All `Interlocked` class methods.
- All `Volatile` class methods (.NET 4.5+).
- Most `SpinLock` methods including `Enter` and `Exit`.
- `Thread.Join`
- `Thread.VolatileRead` and `Thread.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 supplied `BeginInvoke` 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 which `LazyThreadSafetyMode` is specified
Other notable mentions:
- Default add and remove handlers for events in C# since they use `lock` or `Interlocked.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.
Problem
Reading Joseph Albahari's threading tutorial, the following are mentioned as generators of memory barriers: - C#'s `lock` statement (`Monitor.Enter`/`Monitor.Exit`) - All methods on the `Interlocked` class - Asynchronous callbacks that use the thread pool — these include asynchronous delegates, APM callbacks, and Task continuations - Setting and waiting on a signaling construct - Anything that relies on signaling, such as starting or waiting on a Task In addition, Hans Passant and Brian Gideon added the following (assuming none of which already fits into one of the previous categories): - Starting or waking up a thread - Context switch - `Thread.Sleep()` I was wondering if this list was complete (if a complete list could even be practically made) EDIT additions suggested: - Volatile (reading implies an acquire fence, writing implies a release fence)