回顾:
面试题:谈谈对中断的理解
1.谈谈计算机为什么有中断机制
举例子说本质
2.谈谈中断的硬件触发流程
举例子画图看图谈流程
3.谈谈中断软件编程
画图说明四步骤
4.linux内核中断编程
request_irq(中断号,中断处理函数,中断标志,中断名称,给中断处理函数传递的参数)
irqreturn_t 中断处理函数名(中断号,接收传递的参数)
free_irq(中断号,给中断处理函数传递的参数)
5.linux内核对于中断处理函数的要求
执行速度越快越好,更不能休眠操作
6.顶半部和底半部机制
并不是所有的中断处理函数都能满足,势必影响系统的
并发和响应能力,对于这种情况要考虑使用中断编程的顶半部和底半部进行优化
画图说明
7.顶半部特点
本质还是中断处理函数
紧急,耗时较短
不允许CPU资源切换
8.底半部特点
本质就是将某个事件进行延后执行
不紧急,耗时较长
允许CPU资源切换
实现方式:
tasklet
工作队列
软中断
9.tasklet特点
基于软中断实现
延后处理函数不能休眠
优先级高于进程低于硬件中断
struct tasklet_struct
配置函数:
DECLARE_TASKLET //定义初始化
tasklet_schedule //向内核登记,内核会在适当的时候执行
10.工作队列特点
基于进程
延后处理函数可以进行休眠操作
优先级低于软中断低于硬件中断
struct work_struct
配套函数
INIT_WORK //初始化
work_schedule //登记
11.底半部机制之软中断
tasklet本身是基于软中断
软中断的延后处理函数同样不能进行休眠操作
软中断的延后处理函数可以同时运行在多个CPU核上
而tasklet的延后处理函数同一时刻只能运行在一个CPU核上
所以软中断的延后处理函数在设计的时候务必考虑可重入性
软中断编程实现上不能以insmod/rmmod形式动态的安装和卸载
必须和uImage写到一起,这样软件设计相对比较繁琐
tasklet本质就是解决软中断设计的繁琐问题
tasklet就是软中断的一个替代品
2.linux内核软件定时器
2.1.硬件定时器特点
硬件定时器能够按照一定的频率周期性的有规律的给CPU发送中断信号
发送中断的频率(周期)可以通过软件编程来设置
硬件定时器产生的中断信号可以称之为时钟中断
2.2.硬件定时器对应的中断处理函数
硬件定时器产生的中断同样也会有中断处理函数,只是
这个中断处理函数由内核已经帮你写好,此中断处理函数
同样被内核按照一定的频率周期性的有规律的被内核调用
硬件定时器对应的中断处理函数做如下内容:
1.更新系统的运行时间
2.更新实际时间(Wall time)
3.检查当前进程的时间片是否用尽,是否决定进行调度
4.检查是否有超时的内核软件定时器,如果有超时的软件定时器
内核调用超时的软件定时器对应的超时处理函数
5.统计系统的资源,数据信息(top命令查看CPU的利用率)
2.3.linux内核跟时间相关的概念
HZ:是内核的一个全局常量
ARM架构:HZ=100
X86架构:HZ=1000
以ARM架构为例,HZ=100表示硬件定时器一秒钟给CPU发送
100次硬件定时器中断,每发生一次硬件定时器中断的时间
间隔为10ms
jiffies_64:是内核的一个全局变量,64位(unsigned long long)
记录自开机以来,硬件定时器给CPU发送的硬件
定时器中断的次数,每发生一次,jiffies_64自动
加1(由硬件定时器的中断处理函数进行加1)
那也就代表时间上加10ms
jiffies:也是内核的一个全局变量,32位(unsigned long)
它的值取的是jiffies_64的低32位,也就是每发生
一次定时器中断,jiffis_64加1,那也是jiffies加1
jiffies一般用来记录时间间隔(记录流失时间)
切记切记:将来只要在代码中看到jiffies,那就表示当前时刻的时间
参考代码:
unsinged long timeout = jiffies + 5*HZ;
说明:
jiffies:表示代码执行到这条语句对应的当前时刻的时间
5*HZ=5*100=500:表示500次硬件定时器中断,一次为10ms
所以5*HZ表示5秒钟
timeout:5秒以后的时间
unsigned long timeout = jiffies + 2;
说明:
jiffies:表示代码执行到这条语句对应的当前时刻的时间
2:2次硬件定时器中断,共20ms
timeout:20ms以后的时间
案例:分析一下代码的漏洞
unsigned long timeout = jiffies + 5*HZ;
//一堆代码
...
...
...
//以上代码执行完毕,判断是否发生了超时现象
if(jiffies > timeout)
超时
else
没超时
问:linux内核如何解决呢?
答:只需查看内核大神的代码即可
人家怎么写,咱就怎么写
unsigned long timeout = jiffies + 5*HZ;
//一堆代码
...
...
...
//以上代码执行完毕,判断是否发生了超时现象
if(time_after(jiffies, timeout))
超时
else
没超时
作业:认真研读time_after如何解决溢出问题
2.4.linux内核软件定时器
内核软件定时器特点:
可以指定一个超时时间,一旦超时时间到期,内核就会调用
定会器的超时处理函数,切记:linux内核软件定时器基于
软中断实现,所以其超时处理函数不能进行休眠操作
内核描述软件定时器的数据结构:
struct timer_list {
unsigned long expires;
void (*function)(unsigned long data);
unsigned long data;
...
};
成员:
expires:定时器的超时时间
例如:5秒以后超时,expires=jiffies+5*HZ;
function:定时器的超时处理函数,基于软中断实现
所以不能进行休眠操作
形参data:保存传递的参数信息
data:就超时处理函数传递的参数
配套函数:
init_timer(&定时器对象);//初始化定时器对象
注意:还需要额外自己初始化超时时刻的时间
超时处理函数和传递的参数信息(如果有必要)
定时器对象.expires = jiffies+5*HZ; //指定超时时间
定时器对象.function = xxxx_function;//指定超时处理函数
定时器对象.data = (unsigned long)&xxx; //给超时处理函数传递参数
add_timer(&定时器对象);//向内核注册添加一个定时器,
一旦添加完毕,定时器就开始倒计时
一旦时间到期,内核就会调用其超时
处理函数并且将定时器从内核中删除
所以内核定时器的超时处理函数只
执行一次
del_timer(&定时器对象);//从内核中删除定时器
mod_timer(&定时器对象,新的超时时刻的时间);//修改定时器的超时时刻的时间
注意:mod_timer=先del_timer,然后expires=jiffies+20*HZ,最后add_timer
案例1:利用定时器,实现每隔2秒钟打印一句话
案例2:利用定时器,实现每隔2秒钟开关灯
gpio_set_value(led_info[i].gpio,
!gpio_get_value(led_info[i].gpio))
实施步骤:
************************************************
3.linux内核并发和竞态(高级部分)
3.1.分析案例1:要求一个LED设备只能被一个进程打开访问
分析实现过程,有两种方案:
在应用层实现:利用进程间通信的机制实现这个需求
这种实现方式可以实现但是极其之繁琐
在驱动层实现:不管有多少个进程来打开设备,他们都会
调用open函数进行打开,最终他们的open
都会调用到底层驱动的led_open,此时
只需在底层驱动的led_open中做相关一点点
代码限定即可实现需求(一夫当关万夫莫开)
实施步骤:
上位机执行:
mkdir /opt/drivers/day06/2.0
cd /opt/drivers/day06/2.0
vim led_drv.c
vim led_test.c
vim Makefile
make
arm...gcc -o led_test led_test.c
cp led_drv.ko led_test /opt/rootfs/home/drivers
下位机测试:
cd /home/drivers/
insmod led_drv.ko
./led_test & //启动一个A进程,A进程打开设备以后
先不关闭设备,让A进程后台运行
./led_test //启动B进程去打开设备,能否打开成功呢?
结论:虽然此代码能够实现需求,但是此驱动代码中存在
一个严重的漏洞,分析漏洞
分析驱动代码,发现驱动中有一条关键语句:"--open_cnt"
重点来分析"--open_cnt"
分析"--open_cnt"过程:
明确:C语言--open_cnt在汇编语言里对应的是三条语句:
ldr r0, [open_cnt变量对应的内存地址]
sub r0, r0, #1
str r0, [open_cnt变量对应的内存地址]
正常情况:
A进程先打开设备,A进程先执行--open_cnt,汇编看:
先ldr读取:open_cnt=1
然后sub/str修改写回:open_cnt=0
结果:A进程打开成功
然后B进程打开设备,B进程执行--open_cnt,汇编看:
先ldr读取:open_cnt=0
然后sub/str修改写回:open_cnt=-1
结果:B进程打开失败
异常情况(漏洞引起):
A进程先打开设备,A进程先执行--open_cnt,汇编看:
先ldr读取:open_cnt=1
就在此时此刻,由于linux内核支持进程与进程之间的抢占
也就是高优先级的进程会抢占低优先级进程的CPU资源,此时
B进程的优先级高于A进程,CPU资源会从A进程撤下来跑到
B进程去执行,CPU执行B进程之前,先保护A进程当前所有的
ARM寄存器的值到栈中(open_cnt=1压栈),然后B进程将CPU资源归还给A进程时
A进程再从栈中恢复原先的数据
B进程接着执行:
先ldr读取:open_cnt=1
然后sub/str修改写回:open_cnt=0
结果:B进程打开成功
B执行完毕,然后将CPU资源归还给A,A进程接着执行:
A从栈中恢复原先保存的open_cnt=1
然后sub/str修改写回:open_cnt=0
结果:A进程打开成功
总结:造成以上漏洞的根本原因是由于linux内核支持
进程的优先级,支持进程之间抢占CPU资源
3.2.分析案例2:CPU通过某个GPIO给LCD显示屏发送一个固定
周期(10ms)的高低电平(高电平5ms,低电平5ms)
实现过程,软件编程如下:
void lcd_config(void)
{
//拉高
gpio_set_value(PAD_GPIO_B+8, 1);
//让高电平持续5ms
mdelay(5);
//拉低
gpio_set_value(PAG_GPIO_B+8, 0);
//让低电平持续5ms
mdelay(5);
}
此代码运行以后,通过示波器抓取波形,测量这周的时间要大于10ms
分析问题产生的原因:
假如是某个进程来调用此函数配置高低电平,如果当这个
进程刚拉高电平(还没有执行mdelay),此时此刻来了一个
高优先级的进程,或者来一个中断,会将这个进程的CPU资源
抢走,CPU资源进行切换执行处理别的高优先级的进程或者中断
而这个执行过程中,GPIOB8还是持续为高电平,当CPU处理完
高优先级的进程或者中断返回以后在执行mdelay,最终
造成高电平的持续时间势必大于5ms,整个周期势必超时10ms
3.3.通过以上两个案例,得到结论:
在linux内核中,产生以上类似漏洞的四种情形:
1.多核(多个CPU,简称SMP)
多核他们是共享内存,闪存,GPIO等硬件资源
2.同一个CPU上的进程与进程之前的抢占
3.中断和进程(中断的优先级高于进程)
硬件中断和进程
软中断和进程
4.中断和中断(硬件中断优先级高于软中断)
硬件中断和软中断
软中断和软中断
例如:
tasklet_schedule(&tasklet对象);
或者
tasklet_hi_schedule(&tasklet对象);
5.此时此刻务必画出一个简要的四种示意图
3.4.理清相关的概念
并发:多个执行单元(进程和中断)同时发生
竞态:多个执行单元对共享资源的同时访问形成竞争的状态
必须具备一下三个条件:
1.必须有多个执行单元
2.必须有共享资源
3.必须同时访问
共享资源:软件上的全局变量(例如:open_cnt)
或者是硬件资源(例如:GPIOB8,各种控制器的寄存器)
临界区:对共享资源访问的代码区域
//临界区
if(--open_cnt != 0) {
printk("设备已被打开!\n");
open_cnt++;
return -EBUSY;//返回设备忙错误码
}
或者:
//此函数本身就是一个临界区
void lcd_config(void)
{
//拉高
gpio_set_value(PAD_GPIO_B+8, 1);
//让高电平持续5ms
mdelay(5);
//拉低
gpio_set_value(PAG_GPIO_B+8, 0);
//让低电平持续5ms
mdelay(5);
}
互斥访问:当一个执行单元在访问临界区时,其他执行单元禁止
访问临界区,直到访问临界区任务访问完毕
执行路径具有原子性:当某个任务获取到CPU资源踏踏实实访问
临界区时(共享资源),不允许发生CPU资源的
切换,要保证这个任务能够顺利访问临界区
而其他任务等待
3.5.linux内核解决竞态引起的异常(漏洞)的方法
中断屏蔽
自旋锁
信号量
原子操作
3.6.解决竞态引起异常方法之中断屏蔽
面试题:谈谈对中断的理解
1.谈谈计算机为什么有中断机制
举例子说本质
2.谈谈中断的硬件触发流程
举例子画图看图谈流程
3.谈谈中断软件编程
画图说明四步骤
4.linux内核中断编程
request_irq(中断号,中断处理函数,中断标志,中断名称,给中断处理函数传递的参数)
irqreturn_t 中断处理函数名(中断号,接收传递的参数)
free_irq(中断号,给中断处理函数传递的参数)
5.linux内核对于中断处理函数的要求
执行速度越快越好,更不能休眠操作
6.顶半部和底半部机制
并不是所有的中断处理函数都能满足,势必影响系统的
并发和响应能力,对于这种情况要考虑使用中断编程的顶半部和底半部进行优化
画图说明
7.顶半部特点
本质还是中断处理函数
紧急,耗时较短
不允许CPU资源切换
8.底半部特点
本质就是将某个事件进行延后执行
不紧急,耗时较长
允许CPU资源切换
实现方式:
tasklet
工作队列
软中断
9.tasklet特点
基于软中断实现
延后处理函数不能休眠
优先级高于进程低于硬件中断
struct tasklet_struct
配置函数:
DECLARE_TASKLET //定义初始化
tasklet_schedule //向内核登记,内核会在适当的时候执行
10.工作队列特点
基于进程
延后处理函数可以进行休眠操作
优先级低于软中断低于硬件中断
struct work_struct
配套函数
INIT_WORK //初始化
work_schedule //登记
11.底半部机制之软中断
tasklet本身是基于软中断
软中断的延后处理函数同样不能进行休眠操作
软中断的延后处理函数可以同时运行在多个CPU核上
而tasklet的延后处理函数同一时刻只能运行在一个CPU核上
所以软中断的延后处理函数在设计的时候务必考虑可重入性
软中断编程实现上不能以insmod/rmmod形式动态的安装和卸载
必须和uImage写到一起,这样软件设计相对比较繁琐
tasklet本质就是解决软中断设计的繁琐问题
tasklet就是软中断的一个替代品
2.linux内核软件定时器
2.1.硬件定时器特点
硬件定时器能够按照一定的频率周期性的有规律的给CPU发送中断信号
发送中断的频率(周期)可以通过软件编程来设置
硬件定时器产生的中断信号可以称之为时钟中断
2.2.硬件定时器对应的中断处理函数
硬件定时器产生的中断同样也会有中断处理函数,只是
这个中断处理函数由内核已经帮你写好,此中断处理函数
同样被内核按照一定的频率周期性的有规律的被内核调用
硬件定时器对应的中断处理函数做如下内容:
1.更新系统的运行时间
2.更新实际时间(Wall time)
3.检查当前进程的时间片是否用尽,是否决定进行调度
4.检查是否有超时的内核软件定时器,如果有超时的软件定时器
内核调用超时的软件定时器对应的超时处理函数
5.统计系统的资源,数据信息(top命令查看CPU的利用率)
2.3.linux内核跟时间相关的概念
HZ:是内核的一个全局常量
ARM架构:HZ=100
X86架构:HZ=1000
以ARM架构为例,HZ=100表示硬件定时器一秒钟给CPU发送
100次硬件定时器中断,每发生一次硬件定时器中断的时间
间隔为10ms
jiffies_64:是内核的一个全局变量,64位(unsigned long long)
记录自开机以来,硬件定时器给CPU发送的硬件
定时器中断的次数,每发生一次,jiffies_64自动
加1(由硬件定时器的中断处理函数进行加1)
那也就代表时间上加10ms
jiffies:也是内核的一个全局变量,32位(unsigned long)
它的值取的是jiffies_64的低32位,也就是每发生
一次定时器中断,jiffis_64加1,那也是jiffies加1
jiffies一般用来记录时间间隔(记录流失时间)
切记切记:将来只要在代码中看到jiffies,那就表示当前时刻的时间
参考代码:
unsinged long timeout = jiffies + 5*HZ;
说明:
jiffies:表示代码执行到这条语句对应的当前时刻的时间
5*HZ=5*100=500:表示500次硬件定时器中断,一次为10ms
所以5*HZ表示5秒钟
timeout:5秒以后的时间
unsigned long timeout = jiffies + 2;
说明:
jiffies:表示代码执行到这条语句对应的当前时刻的时间
2:2次硬件定时器中断,共20ms
timeout:20ms以后的时间
案例:分析一下代码的漏洞
unsigned long timeout = jiffies + 5*HZ;
//一堆代码
...
...
...
//以上代码执行完毕,判断是否发生了超时现象
if(jiffies > timeout)
超时
else
没超时
问:linux内核如何解决呢?
答:只需查看内核大神的代码即可
人家怎么写,咱就怎么写
unsigned long timeout = jiffies + 5*HZ;
//一堆代码
...
...
...
//以上代码执行完毕,判断是否发生了超时现象
if(time_after(jiffies, timeout))
超时
else
没超时
作业:认真研读time_after如何解决溢出问题
2.4.linux内核软件定时器
内核软件定时器特点:
可以指定一个超时时间,一旦超时时间到期,内核就会调用
定会器的超时处理函数,切记:linux内核软件定时器基于
软中断实现,所以其超时处理函数不能进行休眠操作
内核描述软件定时器的数据结构:
struct timer_list {
unsigned long expires;
void (*function)(unsigned long data);
unsigned long data;
...
};
成员:
expires:定时器的超时时间
例如:5秒以后超时,expires=jiffies+5*HZ;
function:定时器的超时处理函数,基于软中断实现
所以不能进行休眠操作
形参data:保存传递的参数信息
data:就超时处理函数传递的参数
配套函数:
init_timer(&定时器对象);//初始化定时器对象
注意:还需要额外自己初始化超时时刻的时间
超时处理函数和传递的参数信息(如果有必要)
定时器对象.expires = jiffies+5*HZ; //指定超时时间
定时器对象.function = xxxx_function;//指定超时处理函数
定时器对象.data = (unsigned long)&xxx; //给超时处理函数传递参数
add_timer(&定时器对象);//向内核注册添加一个定时器,
一旦添加完毕,定时器就开始倒计时
一旦时间到期,内核就会调用其超时
处理函数并且将定时器从内核中删除
所以内核定时器的超时处理函数只
执行一次
del_timer(&定时器对象);//从内核中删除定时器
mod_timer(&定时器对象,新的超时时刻的时间);//修改定时器的超时时刻的时间
注意:mod_timer=先del_timer,然后expires=jiffies+20*HZ,最后add_timer
案例1:利用定时器,实现每隔2秒钟打印一句话
案例2:利用定时器,实现每隔2秒钟开关灯
gpio_set_value(led_info[i].gpio,
!gpio_get_value(led_info[i].gpio))
实施步骤:
************************************************
3.linux内核并发和竞态(高级部分)
3.1.分析案例1:要求一个LED设备只能被一个进程打开访问
分析实现过程,有两种方案:
在应用层实现:利用进程间通信的机制实现这个需求
这种实现方式可以实现但是极其之繁琐
在驱动层实现:不管有多少个进程来打开设备,他们都会
调用open函数进行打开,最终他们的open
都会调用到底层驱动的led_open,此时
只需在底层驱动的led_open中做相关一点点
代码限定即可实现需求(一夫当关万夫莫开)
实施步骤:
上位机执行:
mkdir /opt/drivers/day06/2.0
cd /opt/drivers/day06/2.0
vim led_drv.c
vim led_test.c
vim Makefile
make
arm...gcc -o led_test led_test.c
cp led_drv.ko led_test /opt/rootfs/home/drivers
下位机测试:
cd /home/drivers/
insmod led_drv.ko
./led_test & //启动一个A进程,A进程打开设备以后
先不关闭设备,让A进程后台运行
./led_test //启动B进程去打开设备,能否打开成功呢?
结论:虽然此代码能够实现需求,但是此驱动代码中存在
一个严重的漏洞,分析漏洞
分析驱动代码,发现驱动中有一条关键语句:"--open_cnt"
重点来分析"--open_cnt"
分析"--open_cnt"过程:
明确:C语言--open_cnt在汇编语言里对应的是三条语句:
ldr r0, [open_cnt变量对应的内存地址]
sub r0, r0, #1
str r0, [open_cnt变量对应的内存地址]
正常情况:
A进程先打开设备,A进程先执行--open_cnt,汇编看:
先ldr读取:open_cnt=1
然后sub/str修改写回:open_cnt=0
结果:A进程打开成功
然后B进程打开设备,B进程执行--open_cnt,汇编看:
先ldr读取:open_cnt=0
然后sub/str修改写回:open_cnt=-1
结果:B进程打开失败
异常情况(漏洞引起):
A进程先打开设备,A进程先执行--open_cnt,汇编看:
先ldr读取:open_cnt=1
就在此时此刻,由于linux内核支持进程与进程之间的抢占
也就是高优先级的进程会抢占低优先级进程的CPU资源,此时
B进程的优先级高于A进程,CPU资源会从A进程撤下来跑到
B进程去执行,CPU执行B进程之前,先保护A进程当前所有的
ARM寄存器的值到栈中(open_cnt=1压栈),然后B进程将CPU资源归还给A进程时
A进程再从栈中恢复原先的数据
B进程接着执行:
先ldr读取:open_cnt=1
然后sub/str修改写回:open_cnt=0
结果:B进程打开成功
B执行完毕,然后将CPU资源归还给A,A进程接着执行:
A从栈中恢复原先保存的open_cnt=1
然后sub/str修改写回:open_cnt=0
结果:A进程打开成功
总结:造成以上漏洞的根本原因是由于linux内核支持
进程的优先级,支持进程之间抢占CPU资源
3.2.分析案例2:CPU通过某个GPIO给LCD显示屏发送一个固定
周期(10ms)的高低电平(高电平5ms,低电平5ms)
实现过程,软件编程如下:
void lcd_config(void)
{
//拉高
gpio_set_value(PAD_GPIO_B+8, 1);
//让高电平持续5ms
mdelay(5);
//拉低
gpio_set_value(PAG_GPIO_B+8, 0);
//让低电平持续5ms
mdelay(5);
}
此代码运行以后,通过示波器抓取波形,测量这周的时间要大于10ms
分析问题产生的原因:
假如是某个进程来调用此函数配置高低电平,如果当这个
进程刚拉高电平(还没有执行mdelay),此时此刻来了一个
高优先级的进程,或者来一个中断,会将这个进程的CPU资源
抢走,CPU资源进行切换执行处理别的高优先级的进程或者中断
而这个执行过程中,GPIOB8还是持续为高电平,当CPU处理完
高优先级的进程或者中断返回以后在执行mdelay,最终
造成高电平的持续时间势必大于5ms,整个周期势必超时10ms
3.3.通过以上两个案例,得到结论:
在linux内核中,产生以上类似漏洞的四种情形:
1.多核(多个CPU,简称SMP)
多核他们是共享内存,闪存,GPIO等硬件资源
2.同一个CPU上的进程与进程之前的抢占
3.中断和进程(中断的优先级高于进程)
硬件中断和进程
软中断和进程
4.中断和中断(硬件中断优先级高于软中断)
硬件中断和软中断
软中断和软中断
例如:
tasklet_schedule(&tasklet对象);
或者
tasklet_hi_schedule(&tasklet对象);
5.此时此刻务必画出一个简要的四种示意图
3.4.理清相关的概念
并发:多个执行单元(进程和中断)同时发生
竞态:多个执行单元对共享资源的同时访问形成竞争的状态
必须具备一下三个条件:
1.必须有多个执行单元
2.必须有共享资源
3.必须同时访问
共享资源:软件上的全局变量(例如:open_cnt)
或者是硬件资源(例如:GPIOB8,各种控制器的寄存器)
临界区:对共享资源访问的代码区域
//临界区
if(--open_cnt != 0) {
printk("设备已被打开!\n");
open_cnt++;
return -EBUSY;//返回设备忙错误码
}
或者:
//此函数本身就是一个临界区
void lcd_config(void)
{
//拉高
gpio_set_value(PAD_GPIO_B+8, 1);
//让高电平持续5ms
mdelay(5);
//拉低
gpio_set_value(PAG_GPIO_B+8, 0);
//让低电平持续5ms
mdelay(5);
}
互斥访问:当一个执行单元在访问临界区时,其他执行单元禁止
访问临界区,直到访问临界区任务访问完毕
执行路径具有原子性:当某个任务获取到CPU资源踏踏实实访问
临界区时(共享资源),不允许发生CPU资源的
切换,要保证这个任务能够顺利访问临界区
而其他任务等待
3.5.linux内核解决竞态引起的异常(漏洞)的方法
中断屏蔽
自旋锁
信号量
原子操作
3.6.解决竞态引起异常方法之中断屏蔽