一、开发环境
1、内核:Linux 2.6.22.6;
2、JZ2440
3、ubuntu 9.10
二、互斥
为了实现同一时绝对的只能有一个进程使用某个设备需要互斥机制,linux互斥机制有多种,如原子变量、互斥锁、信号量、自旋锁、读写锁等等。
1、原子操作。指执行的过程中不会被别的代码路径所中断的操作。实现原子操作过程:
1.1 其常使用的函数有:
static atomic_t canopen = ATOMIC_INIT(1); //定义原子变量并初始化为1
atomic_dec_and_test(atomic_t *v))//自减操作,并检测是否为0,为0返回ture,为1返回false。
atomic_read(atomic_t *v);//读取
atomic_dec(atomic_t *v);//自减1
atomic_inc(atomic_t *v);//自增1
1.2 使用过程
(1)设置原子变量。用来标记设备是否被占用。如定义原子变量canopen:
static atomic_t canopen = ATOMIC_INIT(1); //定义原子变量并初始化为1
(2)在打开设备之前先测试设备是否可用。假设我们用1表示可用,检测函数如下。设备可用时,原子变量减1后为0,检测函数返回ture,非ture为false,则不执行if语句,此时原子变量也变为0,表示设备不可用。下面就可也写使用设备的函数了。
if (!atomic_dec_and_test(&canopen)) //检测,设备不可用执行if语句 { atomic_inc(&canopen); //将原子变量变回原来的值 return -EBUSY; }
(3)在关闭设备的函数里最后把设备标记为未被占用。即使用atomic_inc(atomic_t *v),让原子变量为1,表示设备可用。
使用原子变量,在原子变量加减的时候,不能其他操作打断,因而保证了绝对互斥,同一时间设备只能被一个进程使用。
2、信号量
信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。
只有获取到信号量的进程才能打开设备,获取不到信号量的进程返回或休眠。
2.1 使用函数
定义信号量sem
struct semaphore sem; 初始化信号量 void sema_init (struct semaphore *sem, int val); void init_MUTEX(struct semaphore *sem); //初始化为0
可用使用DECLARE_MUTEX,实现信号量的定义并初始化,如:DECLARE_MUTEX(name); //定义一个信号量name,并初始化它的值为1。
注意init_MUTEX(),DECLARE_MUTEX 在linux2.6.38以后已被移除。其中DECLARE_MUTEX(name)被DEFINE_SEMAPHORE替代,为避免与DEFINE_MUTEX 互斥锁相近引起开发者误解。
获得信号量 void down(struct semaphore * sem); int down_interruptible(struct semaphore * sem); //获取不到休眠,可被中断 int down_trylock(struct semaphore * sem); //获取不到立即返回 释放信号量 void up(struct semaphore * sem);
2.2 使用过程
(1)定义一个信号量。如,定义一个信号量button_lock:
static DECLARE_MUTEX(button_lock); //定义互斥锁
(2)打开设备时先获得信号量。如,
down(&button_lock);
也可用其他函数。第一个进程执行到down函数时可以申请到信号量button_lock,第二个进程如果再申请则申请不到,进入休眠状态,直到信号量被释放,第二个进程就可以进行。
(3)关闭设备最后释放信号量。如,
up(&button_lock);
3、阻塞、非阻塞的实现
3.1 阻塞操作,是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。 非阻塞操作,进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止。
3.2 通过判断函数带入的参数file的file->f_flags来判断是否为阻塞,以做相应的操作。
if (file->f_flags & O_NONBLOCK) { //非阻塞,实现立即返回 } else { //阻塞,实现休眠
}
实现后,应用程序调用实现后的函数时,可以选择阻塞或非阻塞方式,阻塞时陷入休眠,非阻塞时立即返回信息。一般默认是阻塞,应用程序设置非阻塞方式打开使用O_NONBLOCK,如下:
fd = open("...", O_RDWR | O_NONBLOCK);