我在 i686 架构中使用 cmpxchg(比较和交换)进行 32 位比较和交换,如下所示。
(编者注:最初的 32 位示例有问题,但问题不在于它。我相信这个版本是安全的,作为奖励,它也可以为 x86-64 正确编译。 另请注意内联 asm不需要或不建议这样做; __atomic_compare_exchange_n
或更旧的 __sync_bool_compare_and_swap
为 int32_t
或 int64_t
在 i486 和 x86-64 上工作。但这个问题是关于使用内联 asm 进行的你还想。)
// 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;
}
最佳答案
x86_64
指令集有 cmpxchgq
( q
对于四字)8 字节(64 位)比较和交换指令。
还有一个cmpxchg8b
适用于 8 字节数量的指令,但设置起来更复杂,需要您使用 edx:eax
和 ecx:ebx
而不是更自然的 64 位 rax
.这种情况存在的原因几乎可以肯定与英特尔早在 x86_64
之前就需要 64 位比较和交换操作有关。伴随着。它仍然以 64 位模式存在,但不再是唯一的选择。
但是,如前所述,cmpxchgq
可能是 64 位代码的更好选择。
如果需要 cmpxchg 一个 16 字节的对象,cmpxchg8b
的 64 位版本是 cmpxchg16b
.它在最早的 AMD64 CPU 中没有,所以编译器不会为 std::atomic::compare_exchange 生成它。在 16B 对象上,除非您启用 -mcx16
(对于 gcc)。不过,汇编器会对其进行组装,但请注意,您的二进制文件不会在最早的 K8 CPU 上运行。 (这仅适用于 cmpxchg16b
,不适用于 64 位模式下的 cmpxchg8b
或 cmpxchgq
)。
关于gcc - 64 位整数的 cmpxchg 示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/833122/