gpt4 book ai didi

ARM64:LDXR/STXR 与 LDAXR/STLXR

转载 作者:行者123 更新时间:2023-12-01 22:17:55 24 4
gpt4 key购买 nike

在 iOS 上,有两个类似的函数:OSAtomicAdd32OSAtomicAdd32Barrier。我想知道您什么时候需要 Barrier 变体。

拆解后,它们是:

_OSAtomicAdd32:
ldxr w8, [x1]
add w8, w8, w0
stxr w9, w8, [x1]
cbnz w9, _OSAtomicAdd32
mov x0, x8
ret lr

_OSAtomicAdd32Barrier:
ldaxr w8, [x1]
add w8, w8, w0
stlxr w9, w8, [x1]
cbnz w9, _OSAtomicAdd32Barrier
mov x0, x8
ret lr

在哪些场景中您需要后者的加载-获取/存储-释放语义? LDXR/STXR 指令可以重新排序吗?如果可以的话,原子更新是否有可能在没有屏障的情况下“丢失”?从我读到的内容来看,这似乎不会发生,如果是真的,那么为什么需要 Barrier 变体?也许只有当您碰巧也需要 DMB 用于其他目的时?

谢谢!

最佳答案

哦,弱内存排序的令人费解的恐怖......

第一个片段是基本的原子读取-修改-写入 - 如果其他人触摸 x1 指向的任何地址,则存储独占将失败,并且它将再次尝试,直到成功。到目前为止,一切都很好。然而,这只适用于独占监视器覆盖的地址(或更正确的区域),因此虽然它有利于原子性,但对于除此之外的任何同步都无效值。

考虑 CPU1 正在等待 CPU0 将一些数据写入缓冲区的情况。 CPU1 坐在那里等待某种同步对象(比如说信号量),等待 CPU0 更新它以发出新数据准备就绪的信号。

  1. CPU0 写入数据地址。
  2. CPU0 递增恰好位于内存中其他位置的信号量(就像您所做的一样)。
  3. ???
  4. CPU1 看到新的信号量值。
  5. CPU1 读取一些数据,这些数据可能是也可能不是旧数据、新数据或两者的混合。

现在,第 3 步发生了什么?也许这一切都是按顺序发生的。很可能,硬件决定,由于不存在地址依赖性,因此它会让信号量的存储先于数据地址的存储。也许信号量存储命中了缓存,而数据却没有命中。也许这样做只是因为只有那些硬件人员才明白的复杂原因。不管怎样,CPU1 完全有可能在新数据到达内存之前看到信号量更新,从而读回无效数据。

为了解决这个问题,CPU0 必须在步骤 1 和步骤 2 之间设置一个屏障,以确保在写入信号量之前已明确写入数据。让原子写入成为屏障是实现此目的的一种很好的简单方法。然而,由于屏障会严重降低性能,因此在不需要这种完全同步的情况下,您也需要轻量级的无屏障版本。

现在,更不直观的部分是 CPU1 还可以重新排序其负载。同样,由于不存在地址依赖性,因此可以在信号量加载之前自由推测数据加载,而不管 CPU0 的屏障如何。因此,CPU1 在步骤 4 和步骤 5 之间也需要自己的屏障。

对于更权威但相当繁重的版本,请阅读 ARM 的 Barrier Litmus Tests and Cookbook 。请注意,这些东西可能会令人困惑;)

顺便说一句,在这种情况下,获取/释放的架构语义使事情变得更加复杂。由于它们只是单向屏障,而 OSAtomicAdd32Barrier 相对于其前后的代码加起来形成一个完整的屏障,它实际上并不能保证相对于原子操作本身的任何顺序 - 请参阅 this discussion from Linux更多解释。当然,这是从架构的理论角度来看的;实际上,A7 硬件采用连接 LDAXR 来执行 DMB+LDXR 等“简单”选项并非不可想象,这意味着它们可以逃脱这样做是因为他们可以自由地根据自己的实现而不是规范进行编码。

关于ARM64:LDXR/STXR 与 LDAXR/STLXR,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21535058/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com