记忆障碍发生器

时间:2011-07-05 11:22:46

标签: c# memory-barriers

阅读Joseph Albahari's threading tutorial,以下内容被提及为内存障碍的生成器:

  • C#的lock声明(Monitor.Enter / Monitor.Exit
  • Interlocked
  • 上的所有方法
  • 使用线程池的异步回调 - 包括异步委托,APM回调和任务延续
  • 设置和等待信令构造
  • 依赖于信令的任何内容,例如启动或等待任务

此外,Hans Passant和Brian Gideon added the following(假设其中任何一个都不适合以前的类别之一):

  • 启动或唤醒线程
  • 上下文切换
  • Thread.Sleep()

我想知道这个清单是否完整(如果完整清单甚至可以实现)

建议添加

编辑

  • 挥发性(读取意味着获取围栏,写作意味着释放围栏)

3 个答案:

答案 0 :(得分:32)

这是我对这个主题的看法,并尝试在一个答案中提供一个准完整列表。如果我碰到其他人,我会不时编辑我的答案。

通常商定的导致隐含障碍的机制:

  • 所有Monitor类方法,包括C#关键字lock
  • 所有Interlocked类方法。
  • 所有Volatile类方法(.NET 4.5 +)。
  • 大多数SpinLock方法包括EnterExit
  • Thread.Join
  • Thread.VolatileReadThread.VolatileWrite
  • Thread.MemoryBarrier
  • volatile关键字。
  • 启动线程或导致委托在另一个线程上执行的任何内容,包括QueueUserWorkItemTask.Factory.StartNewThread.Start,编译器提供的BeginInvoke方法等。
  • 使用ManualResetEventAutoResetEventCountdownEventSemaphoreBarrier等信令机制
  • 使用Control.InvokeDispatcher.InvokeSynchronizationContext.Post等编组操作

推测(但不确定)导致隐含障碍的机制:

  • Thread.Sleep(由我自己和其他人提出,因为使用此方法可以修复出现内存障碍问题的代码)
  • Thread.Yield
  • Thread.SpinWait
  • Lazy<T>取决于指定的LazyThreadSafetyMode

其他值得注意的提及:

  • 默认添加和删除C#中事件的处理程序,因为它们使用lockInterlocked.CompareExchange
  • x86商店有发布栏语义
  • 尽管ECMA规范没有强制要求,但Microsoft的CLI实现在写入时具有发布范围语义。
  • MarshalByRefObject似乎抑制了子类中的某些优化,这可能使其看起来好像存在隐式内存屏障。感谢Hans Passant发现这一点并引起我的注意。 1

1 这解释了BackgroundWorkervolatile属性的基础字段上没有CancellationPending的情况下正常工作的原因。

答案 1 :(得分:11)

我似乎记得Thread.VolatileRead和Thread.VolatileWrite方法的实现实际上会导致完整的栅栏,而不是半栅栏。

这是非常不幸的,因为人们可能在不知不觉中开始依赖这种行为;他们可能已经编写了一个需要完整围栏的程序,认为他们需要一个半围栏,认为他们正在获得一个半围栏,并且如果这些方法的实现确实提供了一个半围栏,那将会产生令人讨厌的惊喜。

我会避免这些方法。当然,我会避免涉及低锁代码的所有内容,除了最琐碎的案例之外,还不够聪明,不能正确地编写代码。

答案 2 :(得分:3)

volatile关键字也充当了内存屏障。见http://blogs.msdn.com/b/brada/archive/2004/05/12/130935.aspx