我正在开发一个不错的工具,该工具需要两个不同的64位值的原子交换。在amd64架构上,可以使用该XCHGQ
指令(请参阅doc中的警告,警告:这是一个很长的pdf)。
相应地,gcc具有一些原子内建函数,理想情况下它们会做同样的事情,例如在此处可见。
使用这2个文档,我生成了以下简单的C函数,用于两个64位值的原子交换:
void theExchange(u64* a, u64* b) {
__atomic_exchange(a, b, b, __ATOMIC_SEQ_CST);
};
(顺便说一句,对我来说还不是很清楚,为什么需要“原子交换” 3个操作数。)
在我看来,gcc__atomic_exchange
宏使用了3个操作数,因此有点麻烦,所以我测试了它的asm输出。我用a编译了此代码,gcc -O6 -masm=intel -S
并得到以下输出:
.LHOTB0:
.p2align 4,,15
.globl theExchange
.type theExchange, @function
theExchange:
.LFB16:
.cfi_startproc
mov rax, QWORD PTR [rsi]
xchg rax, QWORD PTR [rdi] /* WTF? */
mov QWORD PTR [rsi], rax
ret
.cfi_endproc
.LFE16:
.size theExchange, .-theExchange
.section .text.unlikely
如我们所见,结果函数不仅包含单个数据移动,还包含三个不同的数据移动。因此,据我所理解的这个asm代码,该功能并不是真正的原子。
这怎么可能?也许我误解了一些文档?我承认,gcc内置文档对我来说还不是很清楚。
这是通用版本,__atomic_exchange_n (type *ptr, type val, int memorder)
其中仅进行交换操作ptr
是原子的,而对的读取val
则不是。在通用版本中,val
可通过指针访问,但是原子性仍然不适用于它。指针是这样的,以便在编译器必须调用外部帮助程序时,它可以使用多种大小:
四个非算术函数(加载,存储,交换和compare_exchange)也都具有通用版本。此通用版本适用于任何数据类型。如果特定的数据类型大小使它成为可能,它将使用无锁内置函数。否则,将在运行时解决外部呼叫。此外部调用具有相同的格式,并添加了“ size_t”参数作为第一个参数,该参数指示所指向的对象的大小。所有对象的大小必须相同。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句