开发者

Memory barrier generators

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 followi开发者_如何学Pythonng (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)


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.


I seem to recall that the implementations of the Thread.VolatileRead and Thread.VolatileWrite methods actually cause full fences, not half fences.

This is deeply unfortunate, as people might have come to rely upon this behaviour unknowingly; they might have written a program that requires a full fence, think they need a half fence, think they are getting a half fence, and will be in for a nasty surprise if an implementation of these methods ever does provide a half fence.

I would avoid these methods. Of course, I would avoid everything involving low-lock code, not being smart enough to write it correctly in anything but the most trivial cases.


The volatile keyword acts as a memory barrier too. See http://blogs.msdn.com/b/brada/archive/2004/05/12/130935.aspx

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜