0

我最近阅读了内存屏障中cpu的传递性,作者强调只有一般屏障才能保证传递性。但是,我不能很好地理解它。例如:

CPU 1                      CPU 2                      CPU 3
=======================    =======================    =======================
{ X = 0, Y = 0 }
STORE X=1                  LOAD X                     STORE Y=1
                           <read barrier>             <general barrier>
                           LOAD Y                     LOAD X

假设X在CPU3的缓存中,状态被修改;Y在CPU2的缓存中,状态也被修改。

如果我们在读屏障之前添加写屏障,CPU1 与 CPU2 共享它的存储缓冲区。(它成为一个普遍的障碍)

1) CPU1 在存储缓冲区中设置 X(X=1) 的值。

2) CPU2 从存储缓冲区(共享存储缓冲区)中读取 X 的值。

3)CPU2在存储缓冲区(写屏障)中标记X,并读取无效队列以确保没有来自CPU3的无效消息(读屏障)。

4) CPU2 想要将 X 的缓存行从无效更改为已修改,因此向 CPU3 发送无效消息。

5) CPU3接收到X的无效消息,将其放入无效队列并响应CPU2。

6) CPU2收到response后,将X = 1写入内存或缓存,并加载Y == 0。

...

7) CPU3在执行通用屏障时会发现它的无效队列中有X的无效消息,之后X必须等于1。

没关系,我可以理解。但是,我从perbook的图14.3中阅读了另一个示例,如下所示:

thread0(void) {
    A = 1;
    smp_wb();
    B = 1;
}
thread1(void) {
    while (B == 0)
        continue;
    barrier();
    C = 1;
}
thread2(void) {
    while (C == 0)
        continue;
    barrier();
    assert(A == 1);
}

有一些机会触发断言。作者说将所有障碍更改为 smp_mb 可以在 Quick Quiz 14.2 的回答中修复它。

所以,我的问题是为什么我们需要将 thread1 中的屏障更改为 smp_mb?如果 thread0 和 thread1 在 CPU0 和 CPU1 上运行,并且它们共享一个存储缓冲区。在线程 1 执行 Store C = 1 后,它们的存储缓冲区会爆炸。

[A(wb), B, C]

因为thread2(在CPU2上运行)也使用smp_mb而不是barrier,所以它保证如果看到C == 1,A一定是1。

我在 MESI 内存一致性协议中描述了以上所有内容。也许作者的意思是有另一个协议使 thread1 中的屏障必须代替 smp_mb 来保证 cpu 的传递性?

谁能给我一个例子吗?

也许在特定协议中考虑传递性是一个错误。我们必须记住的是,rmb() 或 wmb() 并不能保证 cpu 的传递性,因为有很多不同的协议和架构。

4

0 回答 0