ARM64:LDXR/STXR与LDAXR/STLXR
在iOS上,有两个类似的函数,ARM64:LDXR/STXR与LDAXR/STLXR,arm,atomic,arm64,Arm,Atomic,Arm64,在iOS上,有两个类似的函数,OSAtomicAdd32和OSAtomicAdd32Barrier。我想知道您何时需要屏障变体 分解后,它们是: _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
OSAtomicAdd32
和OSAtomicAdd32Barrier
。我想知道您何时需要屏障
变体
分解后,它们是:
_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
指令是否可以重新排序?如果可以,在没有屏障的情况下,原子更新是否可能“丢失”?据我所知,这似乎不可能发生,如果是真的,那么为什么需要屏障
变体?也许只有当您碰巧出于其他目的需要一个DMB
谢谢 我猜这只是一种为该操作复制现有架构无关语义的方法 使用
ldaxr
/stlxr
对,如果将AtomicAdd32用作同步机制(互斥/信号量),则上述顺序将确保正确排序,而不管生成的更高级别操作是获取还是释放
所以-这不是关于强制原子添加的一致性,而是关于强制获取/释放互斥体和对该互斥体保护的资源执行的任何操作之间的顺序
它的效率低于在普通本机同步机制中使用的
ldxar
/stxr
或ldxr
/stlxr
,但如果现有的平台无关代码需要使用这些语义进行原子添加,这可能是实现它的最佳方式。,对弱记忆排序的扭曲心灵的恐惧
第一个代码段是基本的原子读-修改-写-如果其他人触摸了x1
指向的任何地址,存储独占将失败,并将重试,直到成功。到现在为止,一直都还不错。但是,这只适用于独占监视器所覆盖的地址(或者更准确地说是区域),因此,虽然这有利于原子性,但对于除该值之外的任何其他值的同步都是无效的
假设CPU1正在等待CPU0将一些数据写入缓冲区。CPU1坐在那里等待某种类型的同步对象(比方说一个信号量),等待CPU0更新它以发出新数据准备就绪的信号
OSAtomicAdd32Barrier
加起来是相对于前后代码的完整屏障,因此实际上并不保证相对于原子操作本身的任何排序-有关更多解释,请参阅。当然,这是从建筑学的理论观点来看的;事实上,A7硬件采用了“简单”的选项,即连接LDAXR
来执行DMB+LDXR
等等,这并非不可想象,这意味着他们可以不受惩罚,因为他们可以自由地为自己的实现而不是规范编写代码。OSAtomicAdd32Barrier()
适用于使用OSAtomicAdd()
进行原子增量以外的操作的人。具体来说,他们正在基于OSAtomicAdd()
实现自己的多处理同步原语。例如,创建自己的互斥体库OSAtomicAdd32Barrier()
使用重屏障指令在原子操作的两侧强制执行内存排序。这在正常使用中是不可取的
总结如下:
1) 如果您只想以线程安全的方式递增整数,请使用OSAtomicAdd32()
2) 如果您被一堆愚蠢地认为OSAtomicAdd32()
可以用作处理器间内存排序和推测屏障的旧代码所困扰,请将其替换为OSAtomicAdd32Barrier()
,感谢您编写的详细答案!我希望我能接受不止一个答案。在发布我的问题之前,我确实读了一点Barrier Litmus测试,但这些答案确实帮助我澄清了困惑。@DaveLee,老实说,这回答了问题:“原子更新是否可能在没有障碍的情况下‘丢失’?”而“已接受”的答案确实如此