Linux基础 -- 跨平台原子操作:ARM 汇编与 C 语言集成

发布于:2024-05-05 ⋅ 阅读:(31) ⋅ 点赞:(0)

1. 汇编语言实现

首先,你需要用 ARM 汇编语言编写比较并交换的功能。这里以 ARMv8 架构为例,因为它直接支持 64 位操作,并且可以较容易地适配 32 位。

// cas.S
// 实现 32 位和 64 位的比较并交换函数
.text
.global cas32
.global cas64

// 32 位比较并交换
// 参数:r0 = *ptr, r1 = oldVal, r2 = newVal
// 返回:旧值在 r0
cas32:
    ldrex r3, [r0]      // 读取 *ptr 到 r3
    cmp   r3, r1        // 比较 r3 和 oldVal
    it    eq            // 如果相等,则执行下一条指令
    strexeq r3, r2, [r0] // 仅当相等时,交换 newVal 和 *ptr 的内容
    mov   r0, r3        // 将旧值 r3 移动到 r0,作为返回值
    dmb                 // 数据内存屏障
    bx    lr            // 返回

// 64 位比较并交换
// 参数:x0 = *ptr, x1 = oldVal, x2 = newVal
// 返回:旧值在 x0
cas64:
    ldxr x3, [x0]       // 读取 *ptr 到 x3
    cmp  x3, x1         // 比较 x3 和 oldVal
    csel x3, x3, x2, eq // 如果相等,则 x3 = x2; 否则 x3 = x3
    stxr w4, x3, [x0]   // 试图将 x3 存入 *ptr
    cbnz w4, cas64      // 如果交换失败,重新尝试
    mov  x0, x3         // 将旧值 x3 移动到 x0,作为返回值
    dmb                 // 数据内存屏障
    ret                 // 返回

2. C 语言接口

接下来,提供一个 C 语言的接口,调用上面实现的汇编函数。

// cas.h
#ifndef CAS_H
#define CAS_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

uint32_t cas32(uint32_t *ptr, uint32_t oldVal, uint32_t newVal);
uint64_t cas64(uint64_t *ptr, uint64_t oldVal, uint64_t newVal);

#ifdef __cplusplus
}
#endif

#endif // CAS_H
// main.c
#include "cas.h"
#include <stdio.h>

int main() {
    uint32_t val32 = 10;
    uint64_t val64 = 20;

    // 尝试使用 CAS 更新 32 位值
    uint32_t old32 = cas32(&val32, 10, 100);
    printf("32-bit CAS: old=%u, new=%u
", old32, val32);

    // 尝试使用 CAS 更新 64 位值
    uint64_t old64 = cas64(&val64, 20, 200);
    printf("64-bit CAS: old=%lu, new=%lu
", old64, val64);

    return 0;
}

3. 编译与连接

aarch64-linux-gnu-gcc  -o cas_demo main.c cas.S

网站公告

今日签到

点亮在社区的每一天
去签到