理解非阻塞线程同步和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没有,还不清楚。
指令需要时间执行的事实并不暗示线程被阻塞了。当一个线程被特别地置于阻塞状态时,它就被阻塞了,而MemoryBarrier()
不这样做。
真正防止指令重排序和缓存刷新的处理器指令需要时间,因为它们必须等待缓存再次一致。在此期间,线程仍被认为在运行。
Update:那么让我们来看看在这个例子中实际发生了什么,以及每个内存屏障实际做了什么。
正如链接所说,1和4确保产生正确的答案。这是因为1确保将答案刷新到内存中,而4确保在检索变量之前刷新读缓存。
2和3确保如果A
先运行,那么B
将始终打印答案。屏障2确保true
的写操作被刷新到内存中,屏障3确保在测试_complete
的值之前刷新读缓存。
缓存和内存刷新应该足够清晰,所以让我们看看指令重排序。编译器、CLR和CPU知道它们可以重新排序指令的方式是通过按顺序分析一组指令。当他们在序列中间看到障碍指令时,他们知道指令不能越过该边界。这不仅保证了缓存的新鲜度,还保证了指令以正确的顺序出现。