在这个线程化的在线书籍中: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还没有做到这一点仍然不清楚。
答案 0 :(得分:5)
指令花费时间执行的事实不意味着线程被阻止。当一个线程被特意置于阻塞状态时被阻塞,MemoryBarrier()
没有阻塞状态。
实际上阻止指令重新排序和缓存刷新的处理器指令需要时间,因为它们必须等待缓存再次变得连贯。在此期间,该线程仍被视为正在运行。
更新:让我们看一下示例中实际发生的事情,以及每个内存障碍实际发生的事情。
正如链接所说,1和4确保产生正确的答案。这是因为1确保将答案刷新到内存中,4确保在检索变量之前刷新读缓存。
2和3确保如果A
先运行,那么B
将始终打印答案。 Barrier 2确保将true
的写入刷新到内存,屏障3确保在测试_complete
的值之前刷新读取的cahces。
缓存和内存刷新应该足够清晰,让我们来看看指令重新排序。编译器,CLR和CPU知道它们可以重新排序指令的方式是按顺序分析一组指令。当他们在序列的中间看到屏障指令时,他们知道指令不能跨越该边界。这确保除了缓存新鲜度之外,指令以正确的顺序发生。