全局变量中断原子操作_保证全局变量读写

区分单独单写、单写多度、多写多

区分操作数长度(很多体系结构、操作系统、甚至编译器、对短数据类型都有原子操作的)

最后才考虑关中断、互斥锁之类的常规保护

关键字 volatile 的使用,原子操作,临界区的使用。 全局变量的使用及保护处查看。

1.关键字 volatile

关键字 volatile 用于告诉编译器,说明被修身的变量可能会被意想不到地改变,防止编译器对代码进行优化。

比如如下程序:

1 ucNms=0x65;

2 ucNms=0x66;

3 ucNms=0x67;

4 ucNms=0x68;

上述 4 条语句,如果变量在声明的时候(unsigned char ucNms;)没有使用 volatile,那么编译器有可能对其优化,只编译最后一条语句 ucNms=0x68;(即忽略前三条语句,只产生一条机器汇编代码);如果变量在声明的时候(volatile unsigned char ucNms;)使用了 volatile,则编译器会逐一地进行编译并产生四条相应的机器代码(产生四条代码)。

精确地说就是,编译器在编译这个变量语句时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。所以下面几个情况在声明的时候需要用 volatile 关键字对其修饰:

1)并行设备的硬件寄存器(如:状态寄存器)

2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

3)多线程应用中被几个任务共享的变量

2.原子操作

所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)

原子操作可以理解为不被打断的操作,可以是一个步骤的操作,也可以是多个步骤的操作,总之确保操作不被打断。

3.临界区

指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。

中断全局变量尽量要用 volatile 修饰,中断全局变量要原子操作访问,要时刻明白中断全局变量是临界区资源,共享访问时需要保护。

另外还有一种无原子锁读操作的方法,由于性能明显低于开关中断的方法,并不推荐对于中断比较敏感的系统也可采用。下面贴出参考代码如下:

4.全局变量的使用及保护

单片机裸机编程,使用全局变量时,一般是一个或多个*.c 文件(或模块)中会使用到某个全局变量(假设为 A),还有中断中也会用到这个全局变量。这样在使用时就要考虑变量的安全性。

首先要明白大循环(后台)对这个变量的访问是依次的,不管全局变量 A 是在哪一个模块或者*.c 文件中,每一个时刻只有一个地方对变量 A 访问。然后中断和中断嵌套程序中也会有对全局变量 A 的访问。

于是就存在这样的问题,大循环(后台)在访问全局变量 A 时(比如说访问到一半时),被中断(前台)程序打断并修改了全局变量 A,这样大循环(后台)程序再次对全局变量 A 访问,就会导致访问到的 A 存在不确定性。从而会影响程序的不正常运行。

这样就可以很明确的知道,只要在大循环(后台)访问 A 时,不让中断(前台)打断其访问即可。确保对 A 的访问是原子操作。于是就有这样的解决方法:

关中断-->>全局变量 A-->>开中断 有的时候,如果访问变量 A 的过程比较长,可以对全局变量 A 做一个副本拷贝 a,用拷贝的 a 作为模块处理的数据。于是就有了这样:

关中断-->>访问全局变量 A-->>副本拷贝 a-->>开中断->>操作副本拷贝 a 这种复杂的情况也可以做一个锁这样做:

大循环(后台):

关中断-->>上锁-->>开中断-->>访问变量 A-->>关中断-->>解锁-->>开中断 中断(前台):

如果是解锁的,操作全局变量 A,如果是上锁的就不操作 当然,如果访问全局变量 A 本身就是一个原子操作(比如一条指令就可以访问完成),这样也就不需要做开关中断的处理了。

示例 1:禁止中断方法保护全局变量

大循环(后台)

ET0=0; //禁止定时中断

访问全局变量 A;

其他代码部分;

ET0=1; //开启允许定时中断

定时器中断(前台)

操作全局变量 A;

示例 2:加锁的方法保护全局变量

大循环(后台)

ET0=0; //禁止定时中断

Lock = 1;

ET0=1; //开启允许定时中断

访问全局变量 A;

其他代码部分;

ET0=0; //禁止定时中断

Lock =0;

ET0=1; //开启允许定时中断

定时器中断(前台)

If(lock ==0) 操作全局变量 A;

else{;} 示例 3:加锁的方法保护全局变量

大循环(后台)

Lock = 1;//若此条语句对应汇编指令是原子操作可以不用开关中断保护此锁

访问全局变量 A;

其他代码部分;

Lock =0;//若此条语句对应汇编指令是原子操作可以不用开关中断保护此锁

定时器中断(前台)

If(lock ==0) 操作全局变量 A;

else{;}

总结下:中断全局变量尽量要用 volatile 修饰,中断全局变量要原子操作访问,要时刻明白中断全局变量是临界区资源,共享访问时需要保护。

另外还有一种无原子锁读操作的方法,由于性能明显低于开关中断的方法,并不推荐对于中断比较敏感的系统也可采用。下面贴出参考代码如下:

AType getA(void){ AType tmp; do { tmp = A; } while(tmp != A); return tmp } 就是两次读取中断中的全局变量 A,判断两次读取值是否相等,相等的话就认为线程中对全局变量 A 的访问没有被打断,返回的访问值是安全可靠的。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
针对全局变量原子操作是指对全局变量读写操作是原子的,不会被中断或干扰。原子操作可以保证多线程环境下对全局变量操作是线程安全的,不会出现数据不一致或冲突的情况。 在多线程环境下,为了保证全局变量原子操作,可以采用以下几种方式: 1. 使用synchronized关键字:通过在方法或代码块上添加synchronized关键字,可以实现对全局变量原子操作。这样可以保证在同一时间只有一个线程可以访问该方法或代码块,从而避免了多个线程同时修改全局变量的问题。 2. 使用volatile关键字:通过使用volatile关键字修饰全局变量,可以确保该变量对所有线程的可见性。当一个线程修改了volatile修饰的全局变量的值时,会立即将该值写入主内存,其他线程在读取该变量时会从主内存中获取最新的值。 3. 使用Lock锁:通过使用Lock接口的实现类(如ReentrantLock)来实现对全局变量原子操作。Lock接口提供了更灵活的加锁和解锁机制,可以更细粒度地控制对全局变量的访问。 需要注意的是,原子操作只能保证对单个变量的操作是原子的,如果多个变量之间存在依赖关系,仍然需要进一步考虑线程安全性。 引用和提到了在多线程环境中,主线程和从线程共享一个全局变量,但TBx只进行读取操作,而全局变量的数值由TA进行维护。这种情况下,可以使用volatile关键字或synchronized关键字来确保全局变量原子操作。 引用提到了在线程对象中定义全局变量并对其进行修改时,会造成多个线程同时修改全局变量的问题。针对这种情况,可以使用synchronized关键字或Lock锁来实现对全局变量原子操作。 综上所述,针对全局变量原子操作可以通过使用synchronized关键字、volatile关键字或Lock锁来实现。这些方法能够确保在多线程环境下对全局变量操作是线程安全的,避免数据不一致或冲突的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [随手记——进程内共享全局变量需要加锁么?](https://blog.csdn.net/weixin_44873133/article/details/119270934)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Java多线程操作局部变量与全局变量](https://blog.csdn.net/weixin_34637138/article/details/114070668)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值