为了实现对临界资源的有效管理,应用层的程序有原子变量,条件变量,信号量来控制并发,同样的问题也存在与驱动开发中,比如一个驱动同时被多个应用层程序调用,此时驱动中的全局变量会同时属于多个应用层进程的进程空间,这种情况下也要使用一些技术来实现对并发的控制。本文将讨论内核中下述并发控制技术的技术特点和应用场景。
中断屏蔽
原子操作
原子变量操作
原子位操作
自旋锁
传统自旋锁
读写自旋锁
顺序锁
RCU
信号量
传统信号量
读写信号量
完成量
互斥量
中断屏蔽
顾名思义,就是屏蔽所有的中断。在嵌入式系统,中断屏蔽可以有三级,1. 硬件接口的屏蔽,2. 硬件GIC的屏蔽,3. CPU(内核)的屏蔽。如果在接口处屏蔽了,那么中断来了就丢了,根本找不到。如果在GIC处屏蔽了,那么在屏蔽期间如果来了irq_1,irq_2,irq_3个中断,因为只有一个pending标志位,所以最后irq_3来的时候会将pending置位,之后解除屏蔽了,CPU发现pending有置位,还是会处理,但是1,2就肯定丢了。在ARM处的屏蔽,即内核中的屏蔽,看怎么设置了,如果就是local_irq_disable,那么丢了就是丢了,和在接口处屏蔽一样,如果是local_irq_save就和第二种一样,追到最后一个中断,内核也有相应的机制进行中断计数,知道这期间来了多少个中断,但是实际操作中,大部分情况我们都不会追着执行错过的中断,除非这个中断非常重要。
我们这里讨论的,就是在内核中进行中断屏蔽。由于内核中很多重要的操作都要依赖于中断,所以屏蔽所有的中断是十分危险的,里面执行的代码要尽可能的快,而且,由于内核的进程调度也是由中断驱动的,所以中断屏蔽中不能有可能引发休眠的代码,否则无法被唤醒。注意,中断屏蔽只是屏蔽了本CPU的中断,所以并不能解决SMP引发的竞泰问题,通常,中断屏蔽要和自旋锁联合使用,用于防止访问自旋锁保护的临界区时被中断打断
普通的中断屏蔽
local_irq_disable(); //屏蔽中断//或local_irq_save(flags); //屏蔽中断并保存目前CPU中的中断位信息/* 临界区 */local_irq_enable(); //解除屏蔽//或local_irq_restore(flags); //解除屏蔽并恢复中断位信息
底半部的中断屏蔽
local_bh_disable(); //屏蔽中断,bh版本的本质是屏蔽了这个CPU上的软中断 /* 临界区 */local_bh_enable();