了解非阻塞线程同步和Thread.MemoryBarrier

时间:2011-08-30 21:40:50

标签: c# .net multithreading

在这个线程化的在线书籍中:http://www.albahari.com/threading/part4.aspx

这是Thread.MemoryBarrier()

的一个例子
   class Foo
{
  int _answer;
  bool _complete;

  void A()
  {
    _answer = 123;
    Thread.MemoryBarrier();    // Barrier 1
    _complete = true;
    Thread.MemoryBarrier();    // Barrier 2
  }

  void B()
  {
    Thread.MemoryBarrier();    // Barrier 3
    if (_complete)
    {
      Thread.MemoryBarrier();       // Barrier 4
      Console.WriteLine (_answer);
    }
  }
}

我们讨论了是否有线程阻塞正在进行?

我认为有一些,特别是考虑到

  

在2010年代的桌面上,完整的围栏需要大约10纳秒。

另一方面,完全围栏只应该disable instructions reodering and caching,它的声音不符合线程阻塞的条件,(不像lock那样明确该线程等待其他人释放锁定之前继续,并在此期间被阻止)

关于该线程的“阻止状态”。我说的不是线程是否被置于阻塞状态,而是是否有一些线程同步发生,这意味着一个线程无法运行而另一个线程无法运行所以,在这种情况下通过MemoryBarrier。

此外,我想清楚地了解每个障碍达到的目标。例如Barrier 2 - 它如何提供新鲜度保证以及它如何连接到屏障3?如果有人会在这里详细解释每个障碍目的(如果不存在1或2或3或4可能会出错)我认为id会大大提高我对此的理解。

编辑:现在大部分时间都清楚1,2和3了。然而,3还没有做到这一点仍然不清楚。

1 个答案:

答案 0 :(得分:5)

指令花费时间执行的事实意味着线程被阻止。当一个线程被特意置于阻塞状态时被阻塞,MemoryBarrier()没有阻塞状态。

实际上阻止指令重新排序和缓存刷新的处理器指令需要时间,因为它们必须等待缓存再次变得连贯。在此期间,该线程仍被视为正在运行。

更新:让我们看一下示例中实际发生的事情,以及每个内存障碍实际发生的事情。

正如链接所说,1和4确保产生正确的答案。这是因为1确保将答案刷新到内存中,4确保在检索变量之前刷新读缓存。

2和3确保如果A先运行,那么B始终打印答案。 Barrier 2确保将true的写入刷新到内存,屏障3确保在测试_complete的值之前刷新读取的cahces。

缓存和内存刷新应该足够清晰,让我们来看看指令重新排序。编译器,CLR和CPU知道它们可以重新排序指令的方式是按顺序分析一组指令。当他们在序列的中间看到屏障指令时,他们知道指令不能跨越该边界。这确保除了缓存新鲜度之外,指令以正确的顺序发生。