目录
一、原子操作实验
使用原子操作来实现对led这个设备互斥访问,即一次只允许一个应用访问LED。
主要思想:
①、在驱动入口函数处初始化原子变量lock为1;
②、每次调用open函数打开设备的时候判断lock的值,如果为负数,则LED正在使用中;
③、LED使用完毕,应用程序调用close时候,将lock加1,恢复成初始化值;
部分代码如下:
static int __init led_init(void)
{
//初始化原子变量为1
atomic_set(&lock, 1);
}
static int led_open()
{
if (!atomic_dec_and_test(&lock))
{
//因为atomic_dec_and_test将lock减1了,退出去必须加1恢复原样
atomic_inc(&lock);
return -1;
}
}
static void led_release()
{
//退出时+1,恢复初始值
atomic_inc(&lock);
}
二、自旋锁实验
如果在open函数中申请自旋锁,在release中释放自旋锁,这样虽然可以实现一次只能有一个应用访问LED,但是不可取,因为自旋锁使用有个注意事项就是保护的区域要尽可能短。所以考虑用一个变量来指示设备的使用情况,在open函数里该变量加1,在release函数中改变了减1,只有该变量为0表示LED可以被使用,大于0表示LED在使用中。我们只需要使用自旋锁保护这个变量即可。
主要思想:
①、在驱动入口函数处初始化自旋锁;
②、每次调用open函数打开设备的时候判断变量的值,如果大于0,则LED正在使用中;如果为0,则将该变量加1,表示设备正在被使用。
③、LED使用完毕,应用程序调用close时候,将该变量减1;
部分代码如下:
考虑兼容性,可以将spin_lock、spin_unlock分别用spin_lock_irqsave、spin_unlock_irqrestore代替。
static int __init led_init(void)
{
//初始化自旋锁
spin_lock_init(&lock);
}
static int led_open()
{
//加锁
spin_lock(&lock);
if (stats)
{
//解锁
spin_unlock(&lock);
return -EBUSY;
}
stats++;
//解锁
spin_unlock(&lock);
}
static void led_release()
{
//加锁
spin_lock(&lock);
if (stats)
stats--;
//解锁
spin_unlock(&lock);
}
三、信号量实验
因为信号量可以引起休眠,因此信号量保护的临界区没有时间限制,这样就可以在open中申请信号量,在release中释放信号量,只要不用再中断里就行了。
部分代码如下:
static int __init led_init(void)
{
//初始化信号量
sema_init(&sem);
}
static int led_open()
{
//申请信号量
down(&sem);
}
static void led_release()
{
//释放信号量
up(&sem);
}
应用程序A获取信号量成功后,sem值减1位为0,应用程序B如果也要使用LED,应为获取不到信号量进入休眠,当A运行完毕后就会释放信号量加1变为1,B就会被唤醒,获取成功开始使用LED。示例结果如下:
四、互斥体
最适合互斥访问的还得用互斥体。与信号量用法类似,部分代码如下:
static int __init led_init(void)
{
//初始化互斥体
mutex_init(&mutex);
}
static int led_open()
{
//获取互斥体
//metho1:可以被信号打断
if (mutex_lock_interruptible(&mutex))
return -ERESTARTSYS;
//methor2:不能被信号打断
mutex_lock(&mutex);
}
static int led_release()
{
//释放互斥体
mutex_unlock(&mutex);
}