• RT-Thread 原子操作(学习)


    原子操作简介

    原子操作(Atomic operation)是指一种不可分割的操作,要么完全执行成功,要么完全不执行。

    原子操作的执行过程中不允许有任何中断,如果出现了中断,那么操作的结果就无法保证。

    原子操作通常用于多线程编程中,保证多个线程之间的并发执行不会出现数据竞争等问题。

    在实现原子操作时,通常使用硬件指令或者操作系统提供的原子操作函数来保证操作的原子性。

    在应用层面,原子操作可以用于实现一些高级的同步和并发控制机制。

    例如,在多线程编程中,如果多个线程都需要访问同一个共享变量,为了避免数据竞争问题,可以使用原子操作来保证堆该变量的操作是原子的。

    以ARM内核执行一个i++操作为例:

    movl i, %eax  //内存访问,读取i变量到cpu的eax寄存器
    addl $1, %eax //修改寄存器的值
    movl %eax, i //将寄存器中的值写回内存
    
    • 1
    • 2
    • 3

    在编译后i++会被编译成三条指令,而这三条指令之间是可能会被系统调度、中断等事件打断的。
    所以,我们在一些场景就需要一气呵成执行完上述操作,原子操作就具备这样的能力。

    原子操作的优点

    在RT-Thread中,我们采取开关全局中断,调度器上锁等方式对临界区资源进行保护,其它OS也会提供类似的操作。

    若采用原子操作后我们可以提供临界区代码的执行效率,大幅提升系统的运行效率,同时也会在一定程度上降低编程的复杂度。

    //采用开关全局中断的方式实现对临界区的保护
    int a = 5;
    level = rt_hw_interrupt_disable();
    a++;
    rt_hw_interrupt_enable(level);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    //采用RT-Thread提供的原子操作API
    int a = 5;
    rt_atomic_add(&a,1);
    
    • 1
    • 2
    • 3

    显然采用原子操作的方式更加简单一些,且避免了开关全局中断带来的性能损失。

    RT-Thread原子操作的实现与使用方法

    RT-Thread对32-bit的ARM,32-bit 的 RISC-V 与 64-bit 的 RISC-V中支持原子操作的内核提供了原子操作支持,使用对应平台的原子操作指令与相关指令实现,默认支持,无需用户关心实现,用户使用时仅需在工程包含rtatomic.h即可使用该文件提供的原子操作API。

    原子读

    rt_atomic_t rt_atomic_load(volatile rt_atomic_t *ptr);
    
    • 1

    使用原子操作方式从ptr地址指向的4字节空间加载一个字。

    原子写

    void rt_atomic_store(volatile rt_atomic_t *ptr, rt_atomic_t val);
    
    • 1

    该操作函数的语义为:使用原子操作方式将val写入ptr地址指向的4字节空间。

    原子数据交换

    rt_atomic_t rt_atomic_exchange(volatile rt_atomic_t *ptr, rt_atomic_t val);
    
    • 1

    该操作函数的语义为:使用原子操作方式将ptr地址指向的4字节空间的数据交换为val,返回ptr地址处修改前的4字节数据。

    原子加

    rt_atomic_t rt_atomic_add(volatile rt_atomic_t *ptr, rt_atomic_t val);
    
    • 1

    使用原子操作方式将 ptr 地址指向的 4 字节数据与 val 相加,将结果写入 ptr 地址指向的 4 字节空间,返回 ptr 地址处修改前的 4 字节数据。

    原子减

    rt_atomic_t rt_atomic_sub(volatile rt_atomic_t *ptr, rt_atomic_t val);
    
    • 1

    该操作函数的语义为:使用原子操作方式将 ptr 地址指向的 4 字节数据减去 val,将结果写入 ptr 地址指向的 4 字节空间,返回 ptr 地址处修改前的 4 字节数据。

    原子标志检查与置位

    rt_atomic_t rt_atomic_flag_test_and_set(volatile rt_atomic_t *ptr);
    
    • 1

    对ptr地址指向的4字节原子标志进行设置,并返回该原子标志对象做设置操作之前的值。
    若ptr地址指向的4字节数据之前状态为0,那么经过此操作之后,该原子标志对象的状态变为了状态1,并且返回0。
    如果ptr地址指向的4字节数据之前为状态1,那么经过此操作之后,它仍然为状态1,并且返回1。

    所以若我们将原子标志对象作为一个“锁来用的话,可判断这个函数接口的返回值,若返回0,则说明锁成功,可以对多线程共享对象做相关的修改操作;如果返回的状态是1,则该原子标志已经被其它线程占用,需要等待释放。

    原子标志清除

    void rt_atomic_flag_clear(volatile rt_atomic_t *ptr);
    
    • 1

    该操作函数的语义为:清除标志,将标志清 0,对 ptr 地址指向原子标志进行清零操作。如果我们将原子标志对象用作“锁”的话,那么执行此操作就相当于释放锁。

    原子比较与交换

    rt_atomic_t rt_atomic_compare_exchange_strong(volatile *ptr,rt_atomic_t *old, rt_atomic_t new);
    
    • 1

    第一个参数指向原子类型对象,第二个参数指向要进行比较的对象,并且如果比较失败,那么该操作会将原子对象的当前值拷贝到该参数所指向的对象中;第三个参数指定存储到原子对象中的值。 如果比较成功,那么 new 值会被存放到原子对象中,并且返回 1;如果比较失败,那么当前原子对象的值会被拷贝到 old 所指向的对象中,并且返回 0。

  • 相关阅读:
    Excel模板1:彩色甘特图
    Kotlin return 和 loop jump
    设计模式之适配器模式
    Swoole v6 能否让 PHP 再次伟大?
    d3dcompiler_47.dll缺失怎么修复,d3dcompiler_47.dll的作用有哪些
    IM系统-消息流化一些常见问题
    BUUCTF [BJDCTF2020]藏藏藏 1
    python爬虫
    提取字母后数字
    Synchronized同步锁
  • 原文地址:https://blog.csdn.net/Caramel_biscuit/article/details/133791760