理解非阻塞线程同步和thread . memorybarrier

本文关键字:同步 thread memorybarrier 线程 | 更新日期: 2023-09-27 18:06:59

在这个线程在线书: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纳秒。

另一方面,full fence只适用于disable instructions reodering and caching,从它的声音来看,它不符合线程阻塞的条件,(不像lock,线程在继续之前很明显等待其他线程释放锁,并在此期间被阻塞)

关于线程'block state'。我说的不是线程是否处于阻塞状态,而是是否有一些线程同步发生,这意味着一个线程不能运行,而其他线程不允许它这样做,在这种情况下,通过MemoryBarrier。

我还想清楚地了解每个障碍的作用。例如,屏障2——它是如何提供新鲜度保证的,它是如何与屏障3联系在一起的?如果有人能详细解释一下这里每个障碍的用途(如果没有1个、2个、3个或4个障碍可能会出什么问题),我想我会大大提高我对这一点的理解。

EDIT:现在已经很清楚1,2和3的作用了。然而,4做了什么,3没有,还不清楚。

理解非阻塞线程同步和thread . memorybarrier

指令需要时间执行的事实并不暗示线程被阻塞了。当一个线程被特别地置于阻塞状态时,它就被阻塞了,而MemoryBarrier()不这样做。

真正防止指令重排序和缓存刷新的处理器指令需要时间,因为它们必须等待缓存再次一致。在此期间,线程仍被认为在运行。

Update:那么让我们来看看在这个例子中实际发生了什么,以及每个内存屏障实际做了什么。

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

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

缓存和内存刷新应该足够清晰,所以让我们看看指令重排序。编译器、CLR和CPU知道它们可以重新排序指令的方式是通过按顺序分析一组指令。当他们在序列中间看到障碍指令时,他们知道指令不能越过该边界。这不仅保证了缓存的新鲜度,还保证了指令以正确的顺序出现。