zoukankan      html  css  js  c++  java
  • 浅谈单片机中变量访问的互斥

    本文以stm32为硬件平台,浅谈一下变量访问的互斥。

    假设是裸板,主程序和中断服务程序都对某个变量进行修改,那么很可能造成数据的不一致。查了一下,主要有两种解决方法:第一种是关中断,在访问公共资源的时候,先把中断关掉,等访问完毕,再打开中断。这样就避免了中断程序和主程序的竞态。第二种是自己做一个互斥锁。

    怎么做互斥锁呢?其实互斥是要依赖与硬件的,如果硬件没有相关的指令或者机制,那就不好办了。

    在x86上,可以用汇编指令XCHG做一个互斥锁,但是stm32上就没有这个指令。在翻阅了《Cortex-M3权威指南》后,我有个发现。下面总结一下:

    互斥访问分为加载和存储,对应的指令对是LDREX/STREX,LDREXH/STREXH,LDREXB/STREXB,分别对应字,半字,字节。

    LDREX/STREX的语法格式为:

    LDREX    Rxf,    [Rn, #offset]    ; 把 (Rn+offset)地址处的内容加载到寄存器 Rxf里

    STREX    Rd, Rxf, [Rn, #offset] ;把Rxf的值存储到(Rn+offset)地址处,这个操作是可以被驳回的(也就是不被执行),如果驳回,Rd的值为1,如果操作成功,Rd的值为0.

    在什么情况下会被驳回呢?在执行STREX的时候,仅当在这之前执行过LDREX指令,且在执行过LDREX指令之后没有其他的STR/STREX指令执行过的时候,才允许执行这个指令。也就是说只有在LDREX执行后的第一条STREX才能成功执行。

    这个道理是易于理解的,在读,改,写的过程中,我们希望读的数据是最新的,也就是读过之后,这个数据不能被别人更新,只能被我更新。如果操作被驳回,说明别人已经修改过了,所以我读出的数据不是最新的,已经“脏了”。

    关于例子文中有,这里就不赘述了。

    用这对指令,就可以做一个互斥锁。怎么做呢?还是以《Cortex-M3权威指南》中的一个例子来说明。

    DeviceALocked是一个位于内存中的R/W变量,用于指示设备A是否已经在使用中。任何一个任务,若欲使用设备A,都必须先检查这个变量的值。如果它的值为零,则表示设备可以使用。在任务获取到设备A后,它要把DeviceALocked的值改为1,表示设备A已经被占用。在设备A使用完毕后,该任务通过重新清零DeviceALocked来释放设备A,从而使其它任务可以使用此设备。 

    TryToLockDeviceA
    LDR   R1, =DeviceALocked

    LDREX R2, [R1]

    CMP   R2, #0          ;检查是否已被锁住 

    BNE LockDeviceAFailed


    DeviceAIsNotLocked
    MOV   R0, #1           ;准备锁住设备A
    STREX R2, R0, [R1]     ;互斥写

    CMP   R2, #0
    BNE LockDeviceAFailed  ;STREX失败,设备A可能已被锁准备返回成功值

    LockDeviceASucceed
    MOV   R0, #0

    POP   {R1, R2, PC}     ;子程序返回 

    LockDeviceAFailed
    MOV   R0, #1

    POP   {R1, R2, PC}     ;子程序返回 





  • 相关阅读:
    bitmap解码
    好用的dos命令
    Navicat Premium 12.0.18 / 12.0.24安装与激活
    Linux基本概念与常用命令
    Hbuilder+MUI(一)
    VS2015 运行项目报错“无可用源”,无法加载“C:WindowsMicrosoft.NETassemblyGAC_MSILSystem.Netv4.0_4.0.0.0__b03f5f7f11d50a3aSystem.Net.dll”这类型错误
    报错:找到了与该请求匹配的多个操作
    ACCESS迁移到SQLSERVE的两种方法
    C# 调用HTTP接口两种方式Demo
    转:WebApi(二)
  • 原文地址:https://www.cnblogs.com/longintchar/p/5224437.html
Copyright © 2011-2022 走看看