You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cortex-M4(STM32G431)平台C++原子RMW序列实现疑问

Cortex-M4(STM32G431)平台原子递增实现的疑问解析

以下是针对4种与ISR共享变量的原子递增实现的疑问,基于STM32G431(Cortex-M4)和g++编译器展开:

实现代码

#include <stm32g4xx.h>
#include <atomic>

namespace  {
    std::atomic_uint32_t a1;
    uint32_t a2;
}

int main(){
    while(true) {
        // Version 1: 手动LDREX/STREX实现原子递增
        uint32_t val;                                            
        do {                                                      
            val = __LDREXW(&a2); 
            val += 1;
        } while ((__STREXW(val, &a2)) != 0U); 
        
        // Version 2: 关中断实现原子递增
        __disable_irq();
        std::atomic_signal_fence(std::memory_order_seq_cst);    // 编译屏障是否必要?
        ++a2;          
        std::atomic_signal_fence(std::memory_order_seq_cst);    // 编译屏障是否必要?
        __enable_irq();
        
        // Version 3: 标准std::atomic默认内存序实现
        std::atomic_fetch_add(&a1, 1);
        
        // Version 4: 标准std::atomic relaxed内存序+编译屏障
        std::atomic_signal_fence(std::memory_order_seq_cst);    // 编译屏障
        std::atomic_fetch_add_explicit(&a1, 1, std::memory_order_relaxed);
        std::atomic_signal_fence(std::memory_order_seq_cst);
    }
}

编译命令

arm-none-eabi-g++ -I../../../STM32CubeG4/Drivers/CMSIS/Core/Include -I../../../STM32CubeG4/Drivers/CMSIS/Device/ST/STM32G4xx/Include -I../../../STM32CubeG4/Drivers/STM32G4xx_HAL_Driver/Inc -DSTM32G431xx -O3 -std=c++23 -fno-exceptions -fno-unwind-tables -fno-rtti -fno-threadsafe-statics  -funsigned-char -funsigned-bitfields -fshort-enums  -ffunction-sections  -fdata-sections  -fconcepts -ftemplate-depth=2048 -fstrict-aliasing -Wstrict-aliasing=1  -Wall -Wextra -I. -mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fverbose-asm -Wa,-adhln -S -o test99.s test.cc

疑问解答

1. Version 1相关疑问

  • 理解正确:进入ISR时Cortex-M内核会自动执行CLREX指令,清除所有独占监视器状态。如果主程序的LDREXW执行后被中断,返回后主程序的STREXW会返回1(操作失败),进入循环重试。
  • ISR无需使用LDREX/STREX:ISR抢占主程序时,已经通过自动CLREX清除了主程序的独占状态,ISR中直接对a2执行普通读写即可(单条指令的读写本身是原子的)。
  • 无法限制CLREX的影响:CLREX是全局清除独占监视器状态,并非针对单个内存地址,只要进入ISR,所有LDREX建立的独占状态都会被清空。

2. Version 2相关疑问

  • __disable_irq()/__enable_irq()是否自带编译屏障取决于CMSIS实现:在g++环境下,CMSIS的这两个函数通常会添加__asm__ __volatile__("" ::: "memory")编译屏障,阻止编译器重排指令。如果是这种情况,显式的std::atomic_signal_fence属于冗余操作;若函数未自带编译屏障,则显式屏障是必要的,防止++a2被编译器移到关/开中断的范围外。
  • 仅禁用修改a2的特定IRQ更利于性能:全局关中断会阻塞所有ISR的响应,增加系统延迟;而通过NVIC_DisableIRQ()只禁用目标IRQ,其他ISR可正常响应,平衡原子性和系统实时性。

3. Version 1与Version 2性能对比

  • 无IRQ触发时:两者周期数接近。Version1的LDREXW+ADD+STREXW+判断仅需4个左右周期(无重试);Version2的CPSID+递增+CPSIE也是3-4个周期,差异可忽略。
  • 有IRQ触发时:Version1会因STREX失败进入循环重试,每次重试都要重复LDREX/ADD/STREX流程,额外占用CPU周期;Version2因关中断不会被打断,操作一次完成,周期数稳定无额外开销。

4. Version 3的DMB指令疑问

  • 单核心Cortex-M4无需DMB:DMB指令的作用是保证内存访问顺序对其他核心可见,而单核心系统中,CPU按顺序执行指令,内存操作的顺序自然符合程序逻辑,冗余的DMB只会增加周期开销,没有实际意义。

5. Version 4是否为单核心首选

  • 是单核心平台的最优实现:采用memory_order_relaxed内存序不会生成冗余的DMB指令,同时std::atomic_signal_fence阻止编译器重排指令,保证原子递增操作的执行范围符合预期,兼顾性能与正确性。

内容的提问来源于stack exchange,提问作者wimalopaan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 18:05:55