【问题标题】:Is the example in the membarrier man page pointless in x86?在 x86 中,membarrier 手册页中的示例是否毫无意义?
【发布时间】:2018-02-08 18:21:25
【问题描述】:

也许只有我一个人,但man 2 页面中membarrier 的示例似乎毫无意义。

基本上,membarrier() 是一个异步内存屏障,给定两个协调的代码段(让我们调用 fast pathslow path)允许您移动所有慢速路径屏障的硬件成本,快速路径只使用编译器屏障1。有几种不同的方法可以实现membarrier 行为,例如向每个涉及的处理器发送 IPI 或等待每个处理器上运行的代码被取消调度 - 但确切的实现细节在这里并不重要。

现在,这是man page 中给出的示例转换:

原码

static volatile int a, b;

static void
fast_path(void)
{
   int read_a, read_b;

   read_b = b;
   asm volatile ("mfence" : : : "memory");
   read_a = a;

   /* read_b == 1 implies read_a == 1. */

   if (read_b == 1 && read_a == 0)
       abort();
}

static void
slow_path(void)
{
   a = 1;
   asm volatile ("mfence" : : : "memory");
   b = 1;
}

转换后的代码

(省略了一些系统调用和初始化样板)

static volatile int a, b;

static void
fast_path(void)
{
   int read_a, read_b;

   read_b = b;
   asm volatile ("" : : : "memory");
   read_a = a;

   /* read_b == 1 implies read_a == 1. */

   if (read_b == 1 && read_a == 0)
       abort();
}

static void
slow_path(void)
{
   a = 1;
   membarrier(MEMBARRIER_CMD_SHARED, 0);
   b = 1;
}

这里slow_path 正在执行两次写入(a,然后是b),由屏障分隔,fast_path 正在执行两次读取(b,然后是a)也由障碍。

但是,x86 内存模型不允许加载-加载或存储-存储重新排序!据我所知,在这种情况下根本不需要membarrier(),原始代码中也不需要mfence。似乎简单的编译器障碍在两个地方就足够了2

一个真正有意义的例子,IMO,应该有一个存储,然后是一个加载,在快速路径中被一个障碍隔开。

我错过了什么吗?


1 编译器屏障防止编译器在其上移动加载或存储(并且根据实现可能会将某些寄存器值强制到内存中),但不会发出任何类型的原子操作或内存栅栏,因此请避免这些指令固有的数量级减速。

2当然在较弱的平台上,可能会发生加载-加载重新排序,该示例可能有意义,但该示例明确是 x86 并且membarrier() 仅在 x86 上实现。

【问题讨论】:

    标签: linux x86 memory-barriers memory-model


    【解决方案1】:

    你是对的。在 x86 上,membarrier() 的这种特殊用法完全没有用。事实上,这个确切的例子是英特尔 SDM 中给出的用于说明 x86 内存排序规则的第一个

    英特尔 SDM 卷。 3 §8.2.3.2 加载和存储都不会使用类似操作重新排序

    【讨论】:

    • @BeeOnRope 实际上,不仅内存屏障和栅栏在 x86 上的这种情况下无用,而且您使用 volatile 甚至不需要编译器屏障(因为编译器可能不会重新排序 volatile 访问 wrt跨序列点)。
    【解决方案2】:

    我正在提交对此手册页的修复,以改用 Dekker 示例。见https://lkml.org/lkml/2017/9/18/779

    顺便说一句,membarrier 系统调用不是 x86 特定的,而是现在在大多数 Linux 架构上实现。

    感谢您的反馈!

    马修

    【讨论】:

    • 感谢您抽出宝贵时间解决此问题!
    • 为什么输入系统调用而不是内存屏障? cpu 可以在进入系统调用后重新排序用户空间指令吗?这导致在内核空间中执行用户空间指令
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多