原子操作
原子操作
原子的引入
在上篇文章并发与竞争中,由于多线程对于共享变量的访问而引入的问题,不符合程序的期望。
为了规避这个问题,引入原子操作,对共享变量不能被打断。
原子操作有两种:原子变量,原子位。
原子变量内核操作
原子变量的内核文件:include/linux/types.h
图 1 原子变量数据类型
对于该变量的具体操作函数:(v是atomic类型的指针)
函数名 |
作用 |
atomic_read(v) |
读出原子变量的值,即v->counter |
atomic_set(v,i) |
设置原子变量的值,即v->counter = i |
atomic_inc(v) |
v->counter++ |
atomic_dec(v) |
v->counter-- |
atomic_add(i,v) |
v->counter += i |
atomic_sub(i,v) |
v->counter -= i |
atomic_inc_and_test(v) |
先加1,再判断新值是否等于0;等于0的话,返回值为1 |
atomic_dec_and_test(v) |
先减1,再判断新值是否等于0;等于0的话,返回值为1 |
疑问:
为什么原子操作为什么可以起作用?原子操作为什么可以不被打断?
打断是因为发生任务调度,如果没有任务调度,就不会有竞争与毛线。而任务调度是基于中断,如果我们把中断关闭,那就不会参数任务调度,进而不会打断。
所以在执行原子操作,必然有对中断的操作。执行之前先关中断,执行完成之后,再将中断打开。(单核处理器)
对于多核处理器,关中断与开中断的时间开销过大,不是采用对中断操作这种方式。原子操作对于变量一般分为三步:读出,修改,写入。比如线程A在修改环节被线程B抢占,
线程B执行完之后。线程A获知目前该共享区域有更新。重新读出,修改,写入,达到一样原子操作的效果。
举例使用
对于个文件,只允许一个app上位机软件使用。使用之后,才允许另外一个app访问。
图 2 原子变量举例使用
原子位
原子变量是一个变量概念,而原子位是1bit,其值对应0和1。对一个的实现在内核中留有接口,
文件具体路劲: /arch/arm/include/asm/bitops.h具体的操作函数如下:
函数名 |
作用 |
set_bit(nr,p) |
设置(*p)的bit nr为1 |
clear_bit(nr,p) |
清除(*p)的bit nr为0 |
change_bit(nr,p) |
改变(*p)的bit nr,从1变为0,或是从0变为1 |
test_and_set_bit(nr,p) |
设置(*p)的bit nr为1,返回该位的老值 |
test_and_clear_bit(nr,p) |
清除(*p)的bit nr为0,返回该位的老值 |
test_and_change_bit(nr,p) |
改变(*p)的bit nr,从1变为0,或是从0变为1;返回该位的老值 |