在 ARM Cortex M 32 位上,在 C 下,我需要维护一个 64 位计数器。我想避免竞争条件,例如:
start:
count = 0x00000000 ffffffff
threadA: increment count_low
count = 0x00000000 00000000
threadB: increment count_low
count = 0x00000000 00000001
threadA: if (!count_low) increment count_high
count = 0x00000000 00000001
threadB: if (!count_low) increment count_high
count = 0x00000000 00000001
这是一个简单的计数器,只有两种使用方式:1. 读取 val 和 2. 递增。
在 ARM 汇编中,无需引入任何锁即可通过
LDREX
和 STREX
完成此操作。但是,我想避免汇编并使用 C。
最好的方法是简单地使用
atomic_uint_least64_t
吗?这行得通吗?
当我尝试制作计数器
atomic_uint_least64_t
时,出现链接器错误 undefined reference to
__atomic_load_8', and when I try adding
-latomic, I get
找不到“-latomic:”没有这样的文件或目录`。
我在 Linux 上使用
arm-none-eabi-gcc
来交叉编译 Cortex M。
只需使用
stdatomic.h
原语。对于任何拱门,他们都会“做正确的事情”。并且,代码将被内联。
对于手臂,他们可能会使用ldrex
。他们可能会使用
dmb
作为记忆屏障。但是,他们也可能使用 ldaxr
这是一个示例程序:#include <stdatomic.h>
unsigned long long ctr;
void
ctrinc(void)
{
atomic_fetch_add(&ctr,1);
}
这是组装:
.arch armv8-a
.file "atom64.c"
.text
.comm ctr,8,8
.align 2
.global ctrinc
.type ctrinc, %function
ctrinc:
adrp x0, :got:ctr
ldr x0, [x0, #:got_lo12:ctr]
.L2:
ldaxr x1, [x0]
add x1, x1, 1
stlxr w2, x1, [x0]
cbnz w2, .L2
nop
ret
.size ctrinc, .-ctrinc
.ident "GCC: (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0"
.section .note.GNU-stack,"",@progbits