了解非阻塞线程同步和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知道它们可以重新排序指令的方式是按顺序分析一组指令。 当他们在序列中间看到屏障指令时 ,他们知道指令不能跨越该边界。 这确保除了缓存新鲜度之外,指令以正确的顺序发生。