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

在这个线程在线书籍: 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 in这个案例。

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

编辑:它现在大部分都清楚1,2和3。 然而,3不能做到的4还不清楚。

指令花费时间执行的事实并不意味着线程被阻止。 当一个线程被特意放入阻塞状态时被阻塞,而MemoryBarrier()不会这样做。

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

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

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

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

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