x86 获取语义获取和递增?

x86 acquire semantics fetch and increment?

假设我有一个时间戳计数器。

 static uint32_t _Atomic timestamp = 0U;

 static inline uint32_t get_ts(void) {
       return atomic_fetch_add_explicit(&timestamp, 1, memory_order_acquire);
 }

假设我有一些并发代码,我想通过实验测试和记录内存重新排序。

 for (;;) {
     uint32_t ts1 = get_ts();
     struct result result_a = do_a();

     uint32_t ts2 = get_ts();
     struct result result_b = do_b();

     log(ts1, &result_a);
     log(ts2, &result_b);
  }

在 c11 内存模型下,do_a 可能会在 get_ts 之后重新排序为 do_b()

 for (;;) {
     uint32_t ts1 = get_ts();
     uint32_t ts2 = get_ts();
     struct result result_b = do_b();
     struct result result_a = do_a();

     log(ts1, &result_a);
     log(ts2, &result_b);
  }

但是,假设编译器不会在 x86 上重新排序 lock xadd 作为所有加载和存储的障碍。因此,x86(但不是编译器)实际上不可能进行这种重新排序,因为 get_ts 调用充当获取释放栅栏。

有没有办法在 x86 上实现真正的获取语义提取和递增?

fetch_add 的 'lock xadd' 实施中有什么不正确的地方?

如果您的意思是您不想要由锁定的 RWM op 提供的完整屏障的更强语义,那么在 x86 上您确实没有任何其他选择。对于加载,普通加载 MOV 指令在这个意义上确实提供了 'true' 获取语义,因为由于存储缓冲,在 MOV 之前按程序顺序执行的存储可能会被其后的其他 CPU 观察到。

是否允许编译器重新排序 do_ado_b 取决于这些函数的作用。 可以对原子进行优化[1], but subject to section 5.1.2.4 of the C11 standard[draft]。 (我相信这是相关的。)

站点 cppreference.com 提供了关于该主题的重新表述的观点,包括 memory_order_acquirememory_order_release 的语义定义。
具有获取语义的加载和具有释放语义的存储可以实现为:

Acquire load                       Release store
Load                               #StoreStore
#LoadLoad                          #LoadStore
#LoadStore                         Store

其中 # 表示栅栏(内存屏障)。
然而,在 Intel memory ordering white paper 中,明确指出 LoadLoad、StoreStore 和 LoadStore 重新排序 never 在时间 loads/stores.
上执行 因此,release-acquire 语义在 x86 上是免费的。

这不是使用像 lock xadd 这样的锁定(从而序列化)指令的问题;发布-获取语义总是受到尊重——即使是简单的 mov 指令。
请注意,获取语义与获取负载之前执行的存储无关;它订购商店并在 之后加载它。

关于你最后一个问题,有点不清楚。

Is there a way on x86 to have a true acquire semantics fetch and increment?

序列化所有指令的实现具有获取语义。在这方面,x86 不做任何重新排序。

如果你的意思是,有没有办法让原子操作顺序不一致(在 C11 的含义中),那么答案是否定的。
您可以在英特尔手册中找到相关部分,但您也可以在上面链接的白皮书中找到它。它说:

  1. In a multiprocessor system, locked instructions have a total order.
  2. Loads and stores are not reordered with locked instructions.

通过要求原子 RMW(读取-修改-写入)操作,您还可以对原子变量强制执行顺序一致的顺序。