c++ - 内存栅栏——需要帮助才能理解

标签 c++ multithreading multicore memory-fences

我正在阅读 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 之后,第二个处理器可以看到存储到 a #1,因为第一个处理器排队存储到“a”并继续存储 b 指令。好的,没关系,我们在#1 和#2 之间的行中添加了一个写栅栏,但是这段代码仍然会失败,因为第二个处理器可能会将无效消息排队,所以我们再添加一个内存栅栏(这次是读栅栏) #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 无效)并通过将读取的 MESI 消息发送到 #4 上的第一个处理器来再次读取它。好的。接下来文章说

Many CPU architectures therefore provide weaker memory-barrier instructions that do only one or the other of these two. Roughly speaking, a “read memory barrier” marks only the invalidate queue and a “write memory barrier” marks only the store buffer. while a full-fledged memory barrier does both.

很好,很清楚,但之后我看到了这个

The effect of this is that a read memory barrier orders only loads on the CPU that executes it, so that all loads preceding the read memory barrier will appear to have completed before any load following the read memory barrier. Similarly, a write memory barrier orders only stores, again on the CPU that executes it, and again so that all stores preceding the write memory barrier will appear to have completed before any store following the write memory barrier.

所以

all loads preceding the read memory barrier will appear to have completed before any load following the read memory barrier

这混淆了之前解释的所有内容。这是什么意思?在加载“a”#4 之前必须完成函数“bar”中的哪个加载?我知道在这个函数中如果没有内存屏障,断言可能会失败,只是因为处理器可能会读取一个旧值,因为它仍然没有设法使其缓存行无效,对象“a”所在的位置。

详细的解释会很有帮助,我整天都在努力理解它。

非常感谢。

最佳答案

这是什么意思?

这意味着如果你有:

read
read
read
READ BARRIER
read
read
read

然后读取屏障充当“连接点”,将这些读取分成两批。读取屏障之前的所有读取都将在读取屏障之后的任何读取开始之前完成。

bar() 中的哪些加载必须在 a (#4) 加载开始之前完成?

b (#3) 的所有读取都必须先于 a (#4) 的任何读取。这意味着 a 直到 b 不再为 0 后才被读取。因为 foo() 使用写屏障来确保 b 更改 (#2) 时,a 已更改为 1 (#1)。因此,这两个障碍共同作用以确保断言语句始终成功。

关于c++ - 内存栅栏——需要帮助才能理解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3999470/

相关文章:

c++ - Qt 中信号槽的层次结构太深

c++ - 同名继承函数和重写虚函数有什么区别?

mysql - Perl/MySQL "Query was empty"错误,可能与多线程相关

delphi - 如何创建一个不终止的控制台应用程序?

cpu-architecture - 两个进程可以在一个 CPU 内核上同时运行吗?

c++ - 为什么 weak_ptr 没有 atomic_{store,load}?

c++ - 使用 rapidjson 从 json 文件中获取数组数据

android - 尝试在Mainactivity中启动线程会使我的程序崩溃

multithreading - R system()进程始终使用相同的CPU,而不是多线程/多核

C 中的缓存管理