ARM64:LDXR / STXR与LDAXR / STLXR

时间:2014-02-03 18:38:43

标签: arm atomic arm64

在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

在哪种情况下你需要后者的Load-Acquire / Store-Release语义?是否可以重新排序LDXR / STXR条款说明?如果可以,原子更新是否有可能在没有障碍的情况下“丢失”?从我所看到的情况来看,似乎不会发生这种情况,如果是真的,那么为什么你需要Barrier变体呢?也许只有当你碰巧需要DMB用于其他目的时?

谢谢!

3 个答案:

答案 0 :(得分:12)

哦,弱记忆秩序的令人费解的恐怖......

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

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

  1. CPU0写入数据地址。
  2. CPU0递增信号量(原子地,就像你那样),恰好在内存的其他地方。
  3. ???
  4. CPU1看到新的信号量值。
  5. CPU1读取某些数据,这些数据可能是也可能不是旧数据,新数据或两者的混合。
  6. 现在,第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等等,这是不可想象的,这意味着他们可以自行解决这个问题,因为他们处于自由状态编写自己的实现,而不是规范。

答案 1 :(得分:8)

OSAtomicAdd32Barrier()适用于那些使用OSAtomicAdd()以外的东西而不仅仅是原子增量的人。具体来说,他们正在基于OSAtomicAdd()实现自己的多处理同步原语。例如,创建自己的互斥库。 OSAtomicAdd32Barrier()使用重屏障指令在原子操作的两侧强制执行内存排序。这在正常使用中是不可取的。

总结:

1)如果您只想以线程安全的方式增加整数,请使用OSAtomicAdd32()

2)如果您遇到一堆愚蠢地认为OSAtomicAdd32()可用作处理器间内存排序和推测障碍的旧代码,请将其替换为OSAtomicAdd32Barrier()

答案 2 :(得分:3)

我猜这只是为这种操作再现现有的与架构无关的语义的一种方式。

使用ldaxr / stlxr对,如果将AtomicAdd32用作同步机制(互斥/信号量),上述序列将确保正确排序 - 无论结果是否为更高级别的操作获得或释放。

所以 - 这不是强制执行原子添加的一致性,而是强制执行获取/释放互斥锁之间的顺序以及对该互斥锁保护的资源执行的任何操作。

它的效率低于您在普通本机同步机制中使用的ldxar / stxrldxr / stlxr,但是如果您现有平台无关代码期望用这些语义添加原子,这可能是实现它的最好方法。