我在i686架构中使用cmpxchg(比较和交换)进行32位比较和交换,如下所示.
(编者注:最初的32位示例是错误的,但问题不在于它.我相信这个版本是安全的,并且作为奖励也可以正确编译x86-64. 另请注意,内联asm不是需要或建议在此; __atomic_compare_exchange_n
或旧的__sync_bool_compare_and_swap
工作int32_t
或int64_t
上的i486和x86-64但这个问题是关于与联汇编这样做,如果你仍然想).
// note that this function doesn't return the updated oldVal static int CAS(int *ptr, int oldVal, int newVal) { unsigned char ret; __asm__ __volatile__ ( " lock\n" " cmpxchgl %[newval], %[mem]\n" " sete %0\n" : "=q" (ret), [mem] "+m" (*ptr), "+a" (oldVal) : [newval]"r" (newVal) : "memory"); // barrier for compiler reordering around this return ret; // ZF result, 1 on success else 0 }
对于64位比较和交换,x86_64架构的等价物是什么
static int CAS(long *ptr, long oldVal, long newVal) { unsigned char ret; // ? return ret; }
paxdiablo.. 7
所述x86_64
指令集具有cmpxchgq
(q
对于8字节(64位)比较和交换为四字)指令.
还有一个cmpxchg8b
指令,将在8字节数量的工作,但它更复杂的设置,需要你用edx:eax
和ecx:ebx
而不是更自然的64位rax
.其存在的原因几乎肯定与英特尔在此之前需要64位比较和交换操作这一事实有关x86_64
.它仍然存在于64位模式,但不再是唯一的选择.
但是,如上所述,cmpxchgq
64位代码可能是更好的选择.
如果你需要cmpxchg一个16字节的对象,64位版本的cmpxchg8b
是cmpxchg16b
.它是最早的AMD64 CPU中缺失的,因此编译器不会为16B对象上的std :: atomic :: compare_exchange生成它,除非你启用-mcx16
(对于gcc).但是汇编程序会组装它,但要注意你的二进制文件不会在最早的K8 CPU上运行.(这仅适用于cmpxchg16b
,不cmpxchg8b
在64位模式,或到cmpxchgq
).
所述x86_64
指令集具有cmpxchgq
(q
对于8字节(64位)比较和交换为四字)指令.
还有一个cmpxchg8b
指令,将在8字节数量的工作,但它更复杂的设置,需要你用edx:eax
和ecx:ebx
而不是更自然的64位rax
.其存在的原因几乎肯定与英特尔在此之前需要64位比较和交换操作这一事实有关x86_64
.它仍然存在于64位模式,但不再是唯一的选择.
但是,如上所述,cmpxchgq
64位代码可能是更好的选择.
如果你需要cmpxchg一个16字节的对象,64位版本的cmpxchg8b
是cmpxchg16b
.它是最早的AMD64 CPU中缺失的,因此编译器不会为16B对象上的std :: atomic :: compare_exchange生成它,除非你启用-mcx16
(对于gcc).但是汇编程序会组装它,但要注意你的二进制文件不会在最早的K8 CPU上运行.(这仅适用于cmpxchg16b
,不cmpxchg8b
在64位模式,或到cmpxchgq
).