我正在阅读Paul E. McKenney的“记忆障碍” http://www.rdrop.com/users/paulmck/scalability/paper/whymb.2010.07.23a.pdf 一切都在详细解释,当我看到一切都清楚时,我会遇到一句话,这会使一切都变得愚蠢,让我觉得我什么都不懂。让我举个例子
void foo(void)
{
a = 1; #1
b = 1; #2
}
void bar(void)
{
while (b == 0) continue; #3
assert(a == 1); #4
}
假设这两个函数在不同的处理器上运行。 现在可能发生的是第二个处理器在存储到b#2之后可以看到存储到#1,因为第一个处理器队列存储到“a”并继续存储b指令。好的,没关系,我们在#1和#2之间的行中添加了写入栅栏,但是这段代码仍然可能失败,因为第二个处理器可能会对invalidate消息进行排队,所以我们再添加一个内存栅栏(这次读取栅栏) #4和#4之间的界限。
void foo(void)
{
a = 1; #1
write_memory_barrier();
b = 1; #2
}
void bar(void)
{
while (b == 0) continue; #3
read_memory_barrier();
assert(a == 1); #4
}
这强制第二个处理器处理所有排队的消息(使a无效)并通过向#4上的第一个处理器发送读MESI消息再次读取它。好。接下来文章说
因此,许多CPU架构 提供较弱的记忆障碍 仅执行一个或多个的指令 这两个中的另一个。粗略地说, “读取内存屏障”仅标记了 使队列无效并“写入内存” 屏障“仅标记存储缓冲区。 一个完整的记忆障碍 做到了。
很好,很清楚,但在那之后我看到了这个
这是一个阅读的效果 内存屏障订单仅加载 执行它的CPU,以便所有 读取存储器之前的负载 障碍似乎已经完成 在读取之前的任何加载之前 记忆障碍。同样,写一个 内存屏障订单只有商店, 再次在执行它的CPU上,和 再次使所有商店前面的 写内存屏障会出现 在任何商店之前完成 遵循写入内存障碍。
所以
读取内存屏障之前的所有负载都将 似乎已经在任何负载跟随之前完成 读取内存屏障
混合了以前解释过的所有内容。这是什么意思?功能“bar”中的哪个负载必须在加载“a”#4之前完成?我理解断言在这个函数中没有内存障碍就会失败,因为处理器可能会读取一个旧值,因为它仍然无法使对象“a”所在的高速缓存行无效。
详细解释会非常有帮助,我试着整天都在理解它。
非常感谢提前。
答案 0 :(得分:10)
这是什么意思?
这意味着如果你有:
read
read
read
READ BARRIER
read
read
read
然后读屏障充当“连接点”,将这些读数分成两批。读取屏障之前的所有读取都将在读取屏障开始后的任何读取之前完成。
在bar()
(#4)的加载开始之前,a
中的哪些加载必须完成?
b
(#3)的所有读取都被强制在a
(#4)的任何读取之前。这意味着在a
不再为0之后才会读取b
。因为foo()
使用了写屏障来确保a
已经更改为1
{(1}}更改时的(#1)(#1)。因此,这两个障碍共同起作用,以确保断言陈述始终成功。