字符设备中的同步、互斥和阻塞操作

下面的内容对学习过程中做一个简单的总结,方便以后回忆,内容可能过于简陋

1. 原子操作

如果我们希望字符驱动程序每次只能给一个应用程序打开,就需要加锁,比如在驱动程序中加一个整型的全局变量canopen:
    1代表可以open,0代表不能open。
但是我们不能简单的给整型变量canopen++或者canopen--,因为代码中简单的自加动作,在汇编代码中就要分成3步完成:
    ldr ... 读出
    add ... 加操作
    str ...  回写值

假如A、B两个程序同时操作变量canopen = 1,在多任务的情况下就会有问题,比如:

                    A                                                                                                    B
        读出canopen,此时值为1
        被切换出执行队列                                                                   读出canopen,此时值为1
                                                                                                        canopen--,此时值为0
                                                                                                        open字符设备成功
        此时A程序重新开始执行,进行canopen--,值为0
        open字符设备也成功

由上面的分析可知,简单的加减是不可靠的,可以使用原子操作:

原子操作指的是在执行过程中不会被别的代码路径所中断的操作。
常用原子操作函数举例:

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。

2. 信号量

信号量(semaphore)是用于保护临界区的一种常用方法,只有得到信号量的进程才能执行临界区代码。
当获取不到信号量时,进程进入休眠等待状态。

定义信号量
struct semaphore sem;
初始化信号量
void sema_init (struct semaphore *sem, int val);
void init_MUTEX(struct semaphore *sem);//初始化为0

也可以用下面的宏定义:
static DECLARE_MUTEX(button_lock);     //定义互斥锁

open时获得信号量:
void down(struct semaphore * sem); //down(&button_lock) //非第一个获取信号量的程序都要进入休眠状态,直到第一个获取信号量的程序释放锁
int down_interruptible(struct semaphore * sem); //加了interruptible,说明就算休眠了也能被别人打断
int down_trylock(struct semaphore * sem);  //down_trylock(&button_lock)

close时释放信号量:
void up(struct semaphore * sem); //up(&button_lock);

3. 阻塞

阻塞操作    
是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。
被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。

非阻塞操作  
进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止。

fd = open("...", O_RDWR | O_NONBLOCK); //传入O_NONBLOCK标志位给底层驱动程序

在驱动程序中就可以这么使用:

if (file->f_flags & O_NONBLOCK)
{
	if (没有检测事件的发生)
		return -EBUSY;
}
else
{
	//进入休眠的状态
	wait_event_interruptible(...);
}

猜你喜欢

转载自blog.csdn.net/lee_jimmy/article/details/83045996