x86/x86_64 实现
x86 平台上,使用 LOCK XADD
指令来实现原子自增:
c++
#include <iostream>
inline int atomic_increment_x86(int* value) {
int result;
__asm__ __volatile__(
"lock xaddl %1, %0"
: "+m"(*value), "=r"(result)
: "1"(1)
: "memory"
);
return result + 1;
}
说明
lock xaddl
指令用于原子地将寄存器的值加到内存变量上,并返回原值。+m(*value)
:+m
表示被修改的内存操作数。"1"(1)
: 约束 1 号操作数使用寄存器,并初始化为1
。memory
作为 clobber 说明该指令会修改内存。
ARM(ARMv7)实现
在 ARM(32 位)上,使用 ldrex
和 strex
指令实现原子操作:
c++
#include <iostream>
inline int atomic_increment_arm(int* value) {
int result, tmp;
__asm__ __volatile__(
"1: ldrex %0, [%2]\n"
" add %0, %0, #1\n"
" strex %1, %0, [%2]\n"
" teq %1, #0\n"
" bne 1b\n"
: "=&r"(result), "=&r"(tmp)
: "r"(value)
: "memory", "cc"
);
return result;
}
说明
ldrex
加载值到result
,并设置独占标志。add
执行加 1 操作。strex
试图存回新值到value
,并检查是否成功(如果strex
失败,则循环重试)。teq %1, #0
检测strex
失败标志,不为 0 时回到1:
处重试。
ARM64(AArch64)实现
在 ARM64(64 位)上,可以使用 ldxr
和 stxr
进行原子操作:
c++
#include <iostream>
inline int atomic_increment_arm64(int* value) {
int result, tmp;
__asm__ __volatile__(
"1: ldxr %w0, [%2]\n"
" add %w0, %w0, #1\n"
" stxr %w1, %w0, [%2]\n"
" cbnz %w1, 1b\n"
: "=&r"(result), "=&r"(tmp)
: "r"(value)
: "memory"
);
return result;
}
说明
ldxr
(load exclusive register)加载value
,并建立独占访问。stxr
(store exclusive register)存储value
,如果失败,则重新加载并重试。cbnz
指令检查stxr
失败标志,不为 0 时回到1:
处重试。
c++封装
c++
#include <iostream>
inline int atomic_increment(int* value) {
#if defined(__x86_64__) || defined(__i386__)
return atomic_increment_x86(value);
#elif defined(__aarch64__)
return atomic_increment_arm64(value);
#elif defined(__arm__)
return atomic_increment_arm(value);
#else
#error "Unsupported architecture"
#endif
}
int main() {
int counter = 0;
std::cout << "Before: " << counter << std::endl;
std::cout << "After: " << atomic_increment(&counter) << std::endl;
return 0;
}