学习原子操作和互斥信号量的使用、阻塞/非阻塞在驱动中的应用。
1 问题
当多个应用程序同时对一个设备文件进行写操作时,可能出现问题。修改程序,使得只有一个应用程序使用驱动程序。
2 原子操作
2.1 原子操作函数
保证了变量操作的原子性。
atomic_t v = ATOMIC_INIT(0);
atomic_read(atomic_t *v);
void atomic_inc(atomic_t *v);
void atomic_dec(atomic_t *v);
int atomic_dec_and_test(atomic_t *v);
2.2 程序
在按键驱动程序的基础上修改。
(1)定义原子变量
atomic_t canopen = ATOMIC_INIT(1);
(2)在.open中判断
if(!atomic_dec_and_test(&canopen))
{
atomic_inc(&canopen);
return -1;
}
(3)在.release中复位
atomic_inc(&canopen);
3 互斥信号量
3.1 互斥信号量函数
获取信号量,则进入临界区;失败,则休眠。
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);
3.2 程序
(1)定义锁
static DECLARE_MUTEX(button_lock);
(2).open添加
down(&button_lock);
(3).release添加
up(&button_lock);
4 阻塞和非阻塞
阻塞:使用down()获取失败,则休眠。
非阻塞:使用down_trylock()获取失败,不休眠,直接放弃。
应用程序在打开设备时可选择使用阻塞方式还是非阻塞方式,例如
fd=open("/dev/buttons",O_RDWR); //使用阻塞操作
fd = open("/dev/buttons ", O_RDWR | O_NONBLOCK); //使用非阻塞操作
底层驱动通过file->f_flags查看应用层设置的参数。
例如,在驱动中,根据应用层的设置,进行不同的处理。
if( file->f_flags & O_NONBLOCK ) //非阻塞操作
{
if(down_trylock(&button_lock) ) //尝试获取信号量,获取不到则退出
return -1;
}
else //阻塞操作
{
down(&button_lock); //获取信号量,获取不到则进入休眠
}