1. 原子操作
atomic_t lock;
/* 原子变量
*/
atomic_set(&gpioled.lock, 1); /* 原子变量初始值为 1 */
/* 通过判断原子变量的值来检查 LED 有没有被别的应用使用 */
/* 通过判断原子变量的值来检查 LED 有没有被别的应用使用 */
if (!atomic_dec_and_test(&gpioled.lock)) {
atomic_inc(&gpioled.lock); /* 小于 0 的话就加 1,使其原子变量等于 0 */
return -EBUSY; /* LED 被使用,返回忙 */
}
atomic_inc(&dev->lock);
2. 信号量
#include <linux/semaphore.h>
struct semaphore sem; /* 信号量 */
sema_init(&gpioled.sem, 1);
/* 获取信号量,进入休眠状态的进程可以被信号打断 */
if (down_interruptible(&gpioled.sem)) {
return -ERESTARTSYS;
}
#if 0
down(&gpioled.sem); /* 不能被信号打断 */
#endif
up(&dev->sem); /* 释放信号量,信号量值加 1 */
当信号量
sem
为
1
的时候表示
LED
灯还没有被使用,如果应用程序
A
要使用
LED
灯,先调用
open
函数打开
/dev/gpioled
,这个时候会获取信号量
sem
,获取成功以后
sem
的
值减
1
变为
0
。如果此时应用程序
B
也要使用
LED
灯,调用
open
函数打开
/dev/gpioled
就会因
为信号量无效
(
值为
0)
而进入休眠状态。当应用程序
A
运行完毕,调用
close
函数关闭
/dev/gpioled
的时候就会释放信号量
sem
,此时信号量
sem
的值就会加
1
,变为
1
。信号量
sem
再次有效,表
示其他应用程序可以使用
LED
灯了,此时在休眠状态的应用程序
B
就会获取到信号量
sem
,获
取成功以后就开始使用
LED
灯。
3. 自旋锁
int dev_stats; /* 设备状态,0,设备未使用;>0,设备已经被使用 */
spinlock_t lock; /* 自旋锁 */
dev_stats = 0;
spin_lock_init(&gpioled.lock);
spin_lock_irqsave(&gpioled.lock, flags); /*上锁 */
if (gpioled.dev_stats) { /* 如果设备被使用了 */
spin_unlock_irqrestore(&gpioled.lock, flags); /* 解锁 */
return -EBUSY;
}
gpioled.dev_stats++; /* 如果设备没有打开,那么就标记已经打开了 */
spin_unlock_irqrestore(&gpioled.lock, flags);/* 解锁 */
/* 关闭驱动文件的时候将 dev_stats 减 1 */
spin_lock_irqsave(&dev->lock, flags); /* 上锁 */
if (dev->dev_stats) {
dev->dev_stats--;
}
spin_unlock_irqrestore(&dev->lock, flags);/* 解锁 */
4. 互斥体
struct mutex lock; /* 互斥体 */
mutex_init(&gpioled.lock);
/* 获取互斥体,可以被信号打断 */
if (mutex_lock_interruptible(&gpioled.lock)) {
return -ERESTARTSYS;
}
#if 0
mutex_lock(&gpioled.lock); /* 不能被信号打断 */
#endif
mutex_unlock(&dev->lock);
互斥体和二值信号量类似,只不过互斥体是专门用于互斥访问的。