嵌入式 C 语言内存屏障深度解析从 volatile 到 DMB/DSB 指令的数据一致性保障机制一、当 DMA 写完数据而 CPU 读到了旧值多核与异步访问的隐蔽陷阱在 ARM Cortex-M7 平台上调试一个双缓冲 DMA 采集系统时遇到了一个令人头疼的问题DMA 完成中断中设置标志位dma_done 1但主循环中读取该标志仍为 0。用逻辑分析仪和 ITM 调试器反复确认DMA 确实已经将数据写入目标缓冲区。问题不在外部硬件而在 CPU 内部——写缓冲Write Buffer与指令重排导致了内存访问顺序与代码书写顺序不一致。这个问题的根因涉及三个层面编译器优化重排编译器在寄存器分配时可能将变量缓存在寄存器中导致对内存的写入延迟。CPU 流水线重排Cortex-M7 支持超标量流水线Load/Store 指令可能互相乱序执行。多核缓存一致性在 Cortex-A 系列多核场景下每个核心的 L1 缓存独立需要显式维护一致性。单纯的volatile关键字只能约束编译器无法约束 CPU 的运行时行为。当代码从单核裸机迁移到多核或带 DMA 的系统时必须引入体系结构级的内存屏障指令。本文从 volatile 的局限性出发逐层深入到 ARMv7-M/ARMv8-A 的 DMB/DSB/ISB 指令构建一个完整的数据一致性保障框架。二、从编译器屏障到 CPU 屏障三层隔离模型内存屏障的本质是在内存访问指令流中插入栅栏强制特定类型的访问在栅栏处完成或排序。按作用域从内到外分为三个层次flowchart TD subgraph L1[第一层编译器屏障] A1[volatile 限定符] -- A2[防止寄存器缓存] A1 -- A3[编译器屏障 asm volatile:::memory] A3 -- A4[约束仅控制编译器不控制 CPU] end subgraph L2[第二层CPU 内存屏障] B1[DMB (Data Memory Barrier)] -- B2[保证数据访问顺序] B3[DSB (Data Synchronization Barrier)] -- B4[等待所有访问完成后才执行后续指令] B5[ISB (Instruction Sync Barrier)] -- B6[刷新流水线重新取指] end subgraph L3[第三层多核缓存一致性] C1[Cortex-A: 核间通信] -- C2[使用共享内存 SEV/WFE 事件] C1 -- C3[必须配合 DMB 确保数据可见性] end L1 -- L2 -- L3 style L1 fill:#1a1a2e,stroke:#16213e,color:#e0e0e0 style L2 fill:#0f3460,stroke:#16213e,color:#e0e0e0 style L3 fill:#533483,stroke:#3a2a6e,color:#e0e0e02.1 volatile 的精确边界volatile告诉编译器该变量可能被外部因素修改如 ISR、DMA、另一个线程因此每次访问都必须从内存读取、每次赋值都必须写入内存。但它存在三个明确限制不保证原子性volatile uint32_t x; x在 ARM 上是 Load-Modify-Store 三条指令中断可能发生在任意两条之间。不影响 CPU 重排编译器生成的指令顺序正确但 CPU 执行时可能以不同顺序执行。不影响缓存策略在多核场景下一个核心对 volatile 变量的写入其他核心的缓存中可能仍是旧值。2.2 DMB 的分层屏障域ARM 的 DMB 指令支持四种屏障域Barrier Domain通过选项参数指定DMB 选项作用域典型场景DMB SY全系统所有观察者可见的全部内存访问多核共享内存同步DMB ST存储屏障仅约束 STORE 操作的顺序DMA 缓冲区写入后通知DMB LD加载屏障仅约束 LOAD 操作的顺序外设状态寄存器轮询DMB ISH内部共享域同一 Inner Shareable Domain 内的观察者Cortex-A 多核同簇间通信以 DMA 场景为例正确的写入-通知模式为// 确保 DMA 描述符写入在启动 DMA 之前对所有观察者可见 dma_desc-src_addr (uint32_t)src_buffer; dma_desc-dst_addr (uint32_t)dst_buffer; dma_desc-length transfer_size; __DMB(); // 数据屏障确保描述符写入完成后... dma_channel-enable 1; // ...才启动 DMA 通道三、生产级代码实现从单核 DMA 到多核共享内存3.1 ARM CMSIS 标准屏障封装/** * file memory_barrier.h * brief ARM 体系结构内存屏障的统一封装。 * * 设计原则: * - 使用 CMSIS 标准宏 __DMB() / __DSB() / __ISB() * - 对不同编译器和架构提供条件编译回退 * - 命名体现屏障用途而非指令名增强代码可读性 */ #ifndef MEMORY_BARRIER_H #define MEMORY_BARRIER_H #include stdint.h #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || \ defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8_1M_MAIN__) /* Cortex-M3/M4/M7/M33/M55: 使用 CMSIS 内置函数 */ #include cmsis_compiler.h #define barrier_data() __DMB() #define barrier_data_st() __DMB() #define barrier_data_sync() __DSB() #define barrier_instr_sync() __ISB() #define barrier_compiler() __DSB() #elif defined(__ARM_ARCH_8A__) || defined(__ARM_ARCH_7A__) /* Cortex-A 系列支持内共享域屏障 */ #define barrier_data() __asm__ volatile(dmb ish ::: memory) #define barrier_data_st() __asm__ volatile(dmb ishst ::: memory) #define barrier_data_sync() __asm__ volatile(dsb ish ::: memory) #define barrier_instr_sync() __asm__ volatile(isb ::: memory) #define barrier_compiler() __asm__ volatile( ::: memory) #else /* 其他架构回退仅编译器屏障 运行时警告 */ #define barrier_data() barrier_compiler() #define barrier_data_st() barrier_compiler() #define barrier_data_sync() barrier_compiler() #define barrier_instr_sync() barrier_compiler() #define barrier_compiler() __asm__ volatile( ::: memory) #warning barrier: 未识别目标架构, 仅提供编译器屏障级别保护 #endif #endif /* MEMORY_BARRIER_H */3.2 DMA 双缓冲传输完整的屏障使用示例/** * brief DMA 双缓冲传输管理器。 * * 核心思路: * - 两个缓冲区轮流使用一个被 DMA 填充一个被 CPU 处理。 * - 使用 DMB 屏障确保 数据到达 rarr; 标志位置位 的可见顺序。 * - 不使用 volatile 加锁依靠硬件 DMA 半满/全满中断驱动状态机。 */ #include memory_barrier.h #define BUF_SIZE 1024 #define BUF_ALIGN 32 typedef enum { BUF_STATE_FREE, /* 可被 DMA 占用 */ BUF_STATE_DMA_FILL, /* DMA 正在写入 */ BUF_STATE_READY, /* 数据就绪, 待 CPU 处理 */ } buf_state_t; typedef struct { uint8_t data[BUF_SIZE] __attribute__((aligned(BUF_ALIGN))); uint32_t filled_len; /* DMA 实际写入的数据量 */ buf_state_t state; /* 0free, 1filling, 2ready */ } dma_buffer_t __attribute__((aligned(BUF_ALIGN))); static dma_buffer_t g_buf[2]; /* 双缓冲 */ void dma_half_complete_callback(uint8_t buf_idx) { /* 半满中断: 前半部分就绪, 通知上层开始处理 */ g_buf[buf_idx].filled_len BUF_SIZE / 2; barrier_data(); /* 确保 filled_len 和 data[0..511] 写入先于 state */ g_buf[buf_idx].state BUF_STATE_READY; } void dma_full_complete_callback(uint8_t buf_idx) { /* 全满中断: 整块就绪 */ g_buf[buf_idx].filled_len BUF_SIZE; barrier_data(); /* 关键屏障: 防止 CPU 在 DMA 数据到达前读取 */ g_buf[buf_idx].state BUF_STATE_READY; /* 切换到另一个缓冲区继续采集 */ uint8_t next_idx buf_idx ^ 1; if (g_buf[next_idx].state BUF_STATE_FREE) { g_buf[next_idx].state BUF_STATE_DMA_FILL; barrier_data(); } } uint8_t* consume_buffer(uint8_t* out_buf_idx, uint32_t* out_len) { /* 主循环消费端: 查找就绪的缓冲区 */ for (uint8_t i 0; i 2; i) { if (g_buf[i].state BUF_STATE_READY) { barrier_data(); /* 确保读取 state 之前的数据访问已同步 */ *out_buf_idx i; *out_len g_buf[i].filled_len; barrier_data(); /* 消费完成后再释放 */ g_buf[i].state BUF_STATE_FREE; return g_buf[i].data; } } return NULL; /* 暂无数据可用 */ }3.3 Cortex-A 多核场景核间共享内存同步/** * brief Cortex-A 多核自旋锁实现基于 ARMv8-A 独占访问指令。 * * 关键设计: * 1. LDREX/STREX 提供原子性DMB 提供顺序性。 * 2. acquire/release 语义通过 DMB LD/DMB ST 实现 * 而非通用的 DMB SY以减少性能开销。 */ typedef struct { uint32_t lock; } spinlock_t __attribute__((aligned(4))); static inline void spinlock_init(spinlock_t* sl) { sl-lock 0; barrier_data_sync(); /* DSB 确保初始化对所有核心可见 */ } static inline void spinlock_acquire(spinlock_t* sl) { uint32_t tmp; __asm__ volatile( 1: ldrex %0, [%1] \n /* 独占加载 */ cmp %0, #0 \n wfene \n /* 未获取到锁时等待事件 */ bne 1b \n mov %0, #1 \n strex %0, %0, [%1] \n /* 独占存储 */ cmp %0, #0 \n bne 1b \n dmb ish \n /* 获取屏障: 后续 Load/Store 不越过此点 */ : r(tmp) : r(sl-lock) : cc, memory ); } static inline void spinlock_release(spinlock_t* sl) { barrier_data(); /* 释放屏障: 前序访问完成后才解锁 */ __asm__ volatile( str %0, [%1] \n /* 直接写入 (无独占要求, 因为我们是持有者) */ dsb ish \n /* 确保写入对其他核心可见 */ sev \n /* 发送事件唤醒等待核心 */ : : r(0), r(sl-lock) : cc, memory ); }四、屏障的代价与替代方案性能敏感场景的权衡内存屏障最直接的代价是流水线停顿。DMB 指令消耗 1~2 个周期DSB 可能消耗数十甚至上百个周期取决于写缓冲区的深度。在 400MHz 的 Cortex-M7 上一次不当的 DSB 可能损失 0.25μs——对于 10kHz 的传感器采样循环来说这意味着 2.5% 的时间被屏障消耗。常见的权衡策略屏障粒度最小化优先使用DMB ST仅约束存储和DMB LD仅约束加载而非DMB SY全约束。DMB ST 在 Cortex-M7 上的延迟约为 DMB SY 的 50%。利用硬件信号替代软件屏障DMA 双缓冲场景下如果每次传输完成由硬件中断驱动可将部分屏障替换为__SEV()/__WFE()事件机制减少轮询开销。审视 volatile 是否足够对于简单的 ISR 标志位单写入者、单读取者、单字节宽度仅使用 volatile 配合编译器屏障即可无需 DMB。判断标准写入者和读取者是否处于不同的内存观察者域如不同的 CPU 核心或 CPU vs DMA 控制器。Cache 策略的配合在 Cortex-A 上将共享数据放置在 non-cacheable 区域可减少缓存一致性问题但会显著降低访问速度。折中方案是使用 Write-Through 缓存策略配合 DMB而非使用 non-cacheable。五、总结内存屏障是嵌入式系统从单核裸机走向多核异构的关键技术桥梁。volatile 解决编译器层面的问题DMB/DSB 解决 CPU 层面的问题而多核缓存一致性策略则解决系统层面的问题。三层之间的配合需要精确理解每一步的语义边界缺一层则嫌不足多一层则伤性能。在日常开发中建议遵循以下原则ISR 与主循环之间的简单标志位使用 volatile 编译器屏障即可满足需求。DMA 缓冲区与 CPU 之间的数据同步必须在状态变量写入前后放置 DMB。多核共享数据的访问必须使用 acquire/release 语义的屏障对DMB LD/DMB ST并配合独占加载/存储指令确保原子性。性能敏感路径中优先使用约束更窄的屏障选项ISH/ST/LD而非 SY 全系统屏障。最后需要强调的是屏障不能弥补数据结构本身的设计缺陷。如果共享数据跨多个 Cache Line即使有屏障保护仍可能发生False Sharing引发的性能退化。正确的做法是先设计好内存布局再考虑同步机制。
嵌入式 C 语言内存屏障深度解析:从 volatile 到 DMB/DSB 指令的数据一致性保障机制
发布时间:2026/7/9 21:38:06
嵌入式 C 语言内存屏障深度解析从 volatile 到 DMB/DSB 指令的数据一致性保障机制一、当 DMA 写完数据而 CPU 读到了旧值多核与异步访问的隐蔽陷阱在 ARM Cortex-M7 平台上调试一个双缓冲 DMA 采集系统时遇到了一个令人头疼的问题DMA 完成中断中设置标志位dma_done 1但主循环中读取该标志仍为 0。用逻辑分析仪和 ITM 调试器反复确认DMA 确实已经将数据写入目标缓冲区。问题不在外部硬件而在 CPU 内部——写缓冲Write Buffer与指令重排导致了内存访问顺序与代码书写顺序不一致。这个问题的根因涉及三个层面编译器优化重排编译器在寄存器分配时可能将变量缓存在寄存器中导致对内存的写入延迟。CPU 流水线重排Cortex-M7 支持超标量流水线Load/Store 指令可能互相乱序执行。多核缓存一致性在 Cortex-A 系列多核场景下每个核心的 L1 缓存独立需要显式维护一致性。单纯的volatile关键字只能约束编译器无法约束 CPU 的运行时行为。当代码从单核裸机迁移到多核或带 DMA 的系统时必须引入体系结构级的内存屏障指令。本文从 volatile 的局限性出发逐层深入到 ARMv7-M/ARMv8-A 的 DMB/DSB/ISB 指令构建一个完整的数据一致性保障框架。二、从编译器屏障到 CPU 屏障三层隔离模型内存屏障的本质是在内存访问指令流中插入栅栏强制特定类型的访问在栅栏处完成或排序。按作用域从内到外分为三个层次flowchart TD subgraph L1[第一层编译器屏障] A1[volatile 限定符] -- A2[防止寄存器缓存] A1 -- A3[编译器屏障 asm volatile:::memory] A3 -- A4[约束仅控制编译器不控制 CPU] end subgraph L2[第二层CPU 内存屏障] B1[DMB (Data Memory Barrier)] -- B2[保证数据访问顺序] B3[DSB (Data Synchronization Barrier)] -- B4[等待所有访问完成后才执行后续指令] B5[ISB (Instruction Sync Barrier)] -- B6[刷新流水线重新取指] end subgraph L3[第三层多核缓存一致性] C1[Cortex-A: 核间通信] -- C2[使用共享内存 SEV/WFE 事件] C1 -- C3[必须配合 DMB 确保数据可见性] end L1 -- L2 -- L3 style L1 fill:#1a1a2e,stroke:#16213e,color:#e0e0e0 style L2 fill:#0f3460,stroke:#16213e,color:#e0e0e0 style L3 fill:#533483,stroke:#3a2a6e,color:#e0e0e02.1 volatile 的精确边界volatile告诉编译器该变量可能被外部因素修改如 ISR、DMA、另一个线程因此每次访问都必须从内存读取、每次赋值都必须写入内存。但它存在三个明确限制不保证原子性volatile uint32_t x; x在 ARM 上是 Load-Modify-Store 三条指令中断可能发生在任意两条之间。不影响 CPU 重排编译器生成的指令顺序正确但 CPU 执行时可能以不同顺序执行。不影响缓存策略在多核场景下一个核心对 volatile 变量的写入其他核心的缓存中可能仍是旧值。2.2 DMB 的分层屏障域ARM 的 DMB 指令支持四种屏障域Barrier Domain通过选项参数指定DMB 选项作用域典型场景DMB SY全系统所有观察者可见的全部内存访问多核共享内存同步DMB ST存储屏障仅约束 STORE 操作的顺序DMA 缓冲区写入后通知DMB LD加载屏障仅约束 LOAD 操作的顺序外设状态寄存器轮询DMB ISH内部共享域同一 Inner Shareable Domain 内的观察者Cortex-A 多核同簇间通信以 DMA 场景为例正确的写入-通知模式为// 确保 DMA 描述符写入在启动 DMA 之前对所有观察者可见 dma_desc-src_addr (uint32_t)src_buffer; dma_desc-dst_addr (uint32_t)dst_buffer; dma_desc-length transfer_size; __DMB(); // 数据屏障确保描述符写入完成后... dma_channel-enable 1; // ...才启动 DMA 通道三、生产级代码实现从单核 DMA 到多核共享内存3.1 ARM CMSIS 标准屏障封装/** * file memory_barrier.h * brief ARM 体系结构内存屏障的统一封装。 * * 设计原则: * - 使用 CMSIS 标准宏 __DMB() / __DSB() / __ISB() * - 对不同编译器和架构提供条件编译回退 * - 命名体现屏障用途而非指令名增强代码可读性 */ #ifndef MEMORY_BARRIER_H #define MEMORY_BARRIER_H #include stdint.h #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || \ defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8_1M_MAIN__) /* Cortex-M3/M4/M7/M33/M55: 使用 CMSIS 内置函数 */ #include cmsis_compiler.h #define barrier_data() __DMB() #define barrier_data_st() __DMB() #define barrier_data_sync() __DSB() #define barrier_instr_sync() __ISB() #define barrier_compiler() __DSB() #elif defined(__ARM_ARCH_8A__) || defined(__ARM_ARCH_7A__) /* Cortex-A 系列支持内共享域屏障 */ #define barrier_data() __asm__ volatile(dmb ish ::: memory) #define barrier_data_st() __asm__ volatile(dmb ishst ::: memory) #define barrier_data_sync() __asm__ volatile(dsb ish ::: memory) #define barrier_instr_sync() __asm__ volatile(isb ::: memory) #define barrier_compiler() __asm__ volatile( ::: memory) #else /* 其他架构回退仅编译器屏障 运行时警告 */ #define barrier_data() barrier_compiler() #define barrier_data_st() barrier_compiler() #define barrier_data_sync() barrier_compiler() #define barrier_instr_sync() barrier_compiler() #define barrier_compiler() __asm__ volatile( ::: memory) #warning barrier: 未识别目标架构, 仅提供编译器屏障级别保护 #endif #endif /* MEMORY_BARRIER_H */3.2 DMA 双缓冲传输完整的屏障使用示例/** * brief DMA 双缓冲传输管理器。 * * 核心思路: * - 两个缓冲区轮流使用一个被 DMA 填充一个被 CPU 处理。 * - 使用 DMB 屏障确保 数据到达 rarr; 标志位置位 的可见顺序。 * - 不使用 volatile 加锁依靠硬件 DMA 半满/全满中断驱动状态机。 */ #include memory_barrier.h #define BUF_SIZE 1024 #define BUF_ALIGN 32 typedef enum { BUF_STATE_FREE, /* 可被 DMA 占用 */ BUF_STATE_DMA_FILL, /* DMA 正在写入 */ BUF_STATE_READY, /* 数据就绪, 待 CPU 处理 */ } buf_state_t; typedef struct { uint8_t data[BUF_SIZE] __attribute__((aligned(BUF_ALIGN))); uint32_t filled_len; /* DMA 实际写入的数据量 */ buf_state_t state; /* 0free, 1filling, 2ready */ } dma_buffer_t __attribute__((aligned(BUF_ALIGN))); static dma_buffer_t g_buf[2]; /* 双缓冲 */ void dma_half_complete_callback(uint8_t buf_idx) { /* 半满中断: 前半部分就绪, 通知上层开始处理 */ g_buf[buf_idx].filled_len BUF_SIZE / 2; barrier_data(); /* 确保 filled_len 和 data[0..511] 写入先于 state */ g_buf[buf_idx].state BUF_STATE_READY; } void dma_full_complete_callback(uint8_t buf_idx) { /* 全满中断: 整块就绪 */ g_buf[buf_idx].filled_len BUF_SIZE; barrier_data(); /* 关键屏障: 防止 CPU 在 DMA 数据到达前读取 */ g_buf[buf_idx].state BUF_STATE_READY; /* 切换到另一个缓冲区继续采集 */ uint8_t next_idx buf_idx ^ 1; if (g_buf[next_idx].state BUF_STATE_FREE) { g_buf[next_idx].state BUF_STATE_DMA_FILL; barrier_data(); } } uint8_t* consume_buffer(uint8_t* out_buf_idx, uint32_t* out_len) { /* 主循环消费端: 查找就绪的缓冲区 */ for (uint8_t i 0; i 2; i) { if (g_buf[i].state BUF_STATE_READY) { barrier_data(); /* 确保读取 state 之前的数据访问已同步 */ *out_buf_idx i; *out_len g_buf[i].filled_len; barrier_data(); /* 消费完成后再释放 */ g_buf[i].state BUF_STATE_FREE; return g_buf[i].data; } } return NULL; /* 暂无数据可用 */ }3.3 Cortex-A 多核场景核间共享内存同步/** * brief Cortex-A 多核自旋锁实现基于 ARMv8-A 独占访问指令。 * * 关键设计: * 1. LDREX/STREX 提供原子性DMB 提供顺序性。 * 2. acquire/release 语义通过 DMB LD/DMB ST 实现 * 而非通用的 DMB SY以减少性能开销。 */ typedef struct { uint32_t lock; } spinlock_t __attribute__((aligned(4))); static inline void spinlock_init(spinlock_t* sl) { sl-lock 0; barrier_data_sync(); /* DSB 确保初始化对所有核心可见 */ } static inline void spinlock_acquire(spinlock_t* sl) { uint32_t tmp; __asm__ volatile( 1: ldrex %0, [%1] \n /* 独占加载 */ cmp %0, #0 \n wfene \n /* 未获取到锁时等待事件 */ bne 1b \n mov %0, #1 \n strex %0, %0, [%1] \n /* 独占存储 */ cmp %0, #0 \n bne 1b \n dmb ish \n /* 获取屏障: 后续 Load/Store 不越过此点 */ : r(tmp) : r(sl-lock) : cc, memory ); } static inline void spinlock_release(spinlock_t* sl) { barrier_data(); /* 释放屏障: 前序访问完成后才解锁 */ __asm__ volatile( str %0, [%1] \n /* 直接写入 (无独占要求, 因为我们是持有者) */ dsb ish \n /* 确保写入对其他核心可见 */ sev \n /* 发送事件唤醒等待核心 */ : : r(0), r(sl-lock) : cc, memory ); }四、屏障的代价与替代方案性能敏感场景的权衡内存屏障最直接的代价是流水线停顿。DMB 指令消耗 1~2 个周期DSB 可能消耗数十甚至上百个周期取决于写缓冲区的深度。在 400MHz 的 Cortex-M7 上一次不当的 DSB 可能损失 0.25μs——对于 10kHz 的传感器采样循环来说这意味着 2.5% 的时间被屏障消耗。常见的权衡策略屏障粒度最小化优先使用DMB ST仅约束存储和DMB LD仅约束加载而非DMB SY全约束。DMB ST 在 Cortex-M7 上的延迟约为 DMB SY 的 50%。利用硬件信号替代软件屏障DMA 双缓冲场景下如果每次传输完成由硬件中断驱动可将部分屏障替换为__SEV()/__WFE()事件机制减少轮询开销。审视 volatile 是否足够对于简单的 ISR 标志位单写入者、单读取者、单字节宽度仅使用 volatile 配合编译器屏障即可无需 DMB。判断标准写入者和读取者是否处于不同的内存观察者域如不同的 CPU 核心或 CPU vs DMA 控制器。Cache 策略的配合在 Cortex-A 上将共享数据放置在 non-cacheable 区域可减少缓存一致性问题但会显著降低访问速度。折中方案是使用 Write-Through 缓存策略配合 DMB而非使用 non-cacheable。五、总结内存屏障是嵌入式系统从单核裸机走向多核异构的关键技术桥梁。volatile 解决编译器层面的问题DMB/DSB 解决 CPU 层面的问题而多核缓存一致性策略则解决系统层面的问题。三层之间的配合需要精确理解每一步的语义边界缺一层则嫌不足多一层则伤性能。在日常开发中建议遵循以下原则ISR 与主循环之间的简单标志位使用 volatile 编译器屏障即可满足需求。DMA 缓冲区与 CPU 之间的数据同步必须在状态变量写入前后放置 DMB。多核共享数据的访问必须使用 acquire/release 语义的屏障对DMB LD/DMB ST并配合独占加载/存储指令确保原子性。性能敏感路径中优先使用约束更窄的屏障选项ISH/ST/LD而非 SY 全系统屏障。最后需要强调的是屏障不能弥补数据结构本身的设计缺陷。如果共享数据跨多个 Cache Line即使有屏障保护仍可能发生False Sharing引发的性能退化。正确的做法是先设计好内存布局再考虑同步机制。