关于内存障碍(为什么以下示例是错误的)

时间:2014-11-10 15:01:05

标签: cpu compiler-optimization cpu-cache memory-barriers

我读了一篇文章, https://www.kernel.org/doc/Documentation/memory-barriers.txt

在本文档中,显示了以下示例 所以不要忘记ACCESS_ONCE()。

尝试在两者上的相同商店强制执行订购是很诱人的 "如果"的分支声明如下:

q = ACCESS_ONCE(a);
if (q) {
    barrier();
    ACCESS_ONCE(b) = p;
    do_something();
} else {
    barrier();
    ACCESS_ONCE(b) = p;
    do_something_else();
}

不幸的是,目前的编译器会将其转换为高位 优化级别:

q = ACCESS_ONCE(a);
barrier();
ACCESS_ONCE(b) = p;  /* BUG: No ordering vs. load from a!!! */
if (q) {
    /* ACCESS_ONCE(b) = p; -- moved up, BUG!!! */
    do_something();
} else {
    /* ACCESS_ONCE(b) = p; -- moved up, BUG!!! */
    do_something_else();
}

我不知道,为什么"向上移动"是个bug?如果我编写代码,我将移动" ACCESS_ONE(b),因为if / else分支都执行相同的代码。

1 个答案:

答案 0 :(得分:1)

向上移动并不是一个错误,而是它暴露了代码中的错误。

目的是在q(来自a)上使用条件,以确保在b读取之后写入a;因为两个商店都受条件“保护”并且“商店没有被推测”,所以在知道条件的结果之前,CPU不应该进行存储,这需要首先完成读取。

编译器通过看到条件的两个分支以相同的东西开始而失败了这个意图,因此在正式意义上这些语句条件。下一段解释了这个问题:

  

现在“a”和商店的加载之间没有条件   'b',表示CPU有权对它们进行重新排序:   条件是绝对必需的,并且必须存在于   在应用了所有编译器优化之后,甚至是汇编代码。

我没有足够的经验知道barrier()究竟是什么意思,但显然它不足以强制执行两个独立内存操作之间的顺序。