12.5重写按键驱动——同步互斥阻塞
前言:
思考,我们写的按键驱动,可能会出现多个应用程序打开同一个驱动。
测试确实如此,有三个一样的进程,不同PID:
怎么保证同一时刻只能有一个程序打开呢。我们想可以用如下代码实现:
int canopen =1;
然而,实际--canopen在硬件操作分为三步:
-
从寄存器读出
-
修改
-
写回寄存器
在这三个过程中,随时可能发生被另外一个程序所打断。
那有没有一种机制可以不被打断,有的,有下面几种方法:
1.原子操作
2.信号量
3.阻塞
一.同步互斥阻塞之原子操作
1.定义:
所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束
原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中的一部分。将整个操作视作一个整体是原子性的核心特征。
2.常用原子操作函数举例:
atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0
atomic_read(atomic_t *v); //返回原子变量的值
void atomic_inc(atomic_t *v); //原子变量增加1
void atomic_dec(atomic_t *v); //原子变量减少1
int atomic_dec_and_test(atomic_t *v); //自减操作后测试其是否为0,为0则返回true,否则返回false。
3.改代码:
测试:(互斥阻塞)
二.同步互斥阻塞之信号量
1.定义:
信号量(semaphore)是用于保护临界区的一种常用方法,只有得到信号量的进程才能执行临界区代码。
当获取不到信号量时,进程进入休眠等待状态。
定义信号量
struct semaphore sem;
初始化信号量
void sema_init (struct semaphore *sem, int val);
void init_MUTEX(struct semaphore *sem);//初始化为0
static DECLARE_MUTEX(button_lock); //定义互斥锁
获得信号量
void down(struct semaphore * sem);
int down_interruptible(struct semaphore * sem);
int down_trylock(struct semaphore * sem);
释放信号量
void up(struct semaphore * sem);
更改代码:
测试:
一开始运行运行两次测试程序,ps查看:一个处于睡眠等待按键状态,一个处于僵死状态(在down休眠)
执行kill -9 774后,立马打印secondddrv_butttons_fasync
再次ps,原先那个僵死的进程变成睡眠状态
三.同步互斥阻塞之阻塞
阻塞操作
是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。
被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。
非阻塞操作
进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止。
fd = open("...", O_RDWR | O_NONBLOCK); //有O_NONBLOCK为非阻塞,没有默认阻塞