一步一步走进字符驱动--自旋锁
前面说到原子操作和今天的自旋锁,以及信号量等.都是为了防止抢占式操作系统和SMP所带来的竞态的发生.那么什么叫竞态呢?相信很多学过linux系统编程和window 开发的都知道.当一个进程在访问一个公共资源时,由于时间片时间到或者被抢占等,会导致其他进程运行,有可能也访问该资源.那么就会修改这份资源,导致本来的进程再此操作这份资源时,资源内的数据已被修改..由于这种情况,所以操作系统才引出各种锁来锁定公共资源来达到资源的保护.
今天我们大致看一下自旋锁.
简介:
自旋锁是一种典型的对临界区资源进行互斥访问的手段,其名称是根据它的工作方式得来的.为了获得自旋锁,在某CPU上运行的代码需先执行一个原子操作,该操作测试并设置某一内存变量,由于它是原子操作,所以在该操作完成之前其他执行单元不能访问这个内存变量.如果测试结果表明锁已经空闲,则程序获得这个自旋锁并继续执行,如果测试表明锁仍被占用,程序将在一个小的循环内重复这个"测试并设置"操作,即进行所谓的"自旋",就是原子打转.
自旋锁定义: linux/Spinlock.h
typedef struct spinlock {
union {
struct raw_spinlock rlock;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
#define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
struct {
u8 __padding[LOCK_PADSIZE];
struct lockdep_map dep_map;
};
#endif
};
} spinlock_t;
1:定义自旋锁
spinlock_t lock;
2:初始化自旋锁
spin_lock_init(lock); //该宏用于动态初始化自旋锁
3:获得自旋锁
static inline void spin_lock(spinlock_t *lock); //获取自旋锁,若能获取,则立即返回,否则自选在这等待获取
static inline int spin_trylock(spinlock_t *lock); //尝试获取自旋锁,若能获取则返回TRUE,否则返回FALSE,不原地自选
4:释放自旋锁
static inline void spin_unlock(spinlock_t *lock); //释放获得的自旋锁
示例:
/*定义一个自旋锁*/
spinlock_t lock;
spin_lock_init(lock);
spin_lock(&lock); //获取自旋锁
/*临界区资源*/
spin_unlock(&lock); //释放自旋锁
由于自旋锁在自旋时不能被中断打断,否则将锁死,所以延伸出带中断的自旋锁
static inline void spin_lock_irq(spinlock_t *lock);
static inline void spin_unlock_irq(spinlock_t *lock);
#define spin_lock_irqsave(spinlock_t *lock, flags);
static inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
static inline void spin_lock_bh(spinlock_t *lock);
static inline void spin_unlock_bh(spinlock_t *lock);
自旋锁主要针对单SMP和单CPU但支持抢占式的情况,对于单CPU和内核不支持抢占式的话,自旋锁会退化成空操作.
自旋锁实现设备打开唯一性,示例代码:
spinlock_t lock;
int global_count = 0; //定义文件被打开的次数
int global_mem_open(struct inode *inode, struct file *filp)
{
/*将设备结构体指针赋给文件私有数据指针*/
struct globalmem_dev *devp;
devp = container_of(inode->i_cdev,struct globalmem_dev,cdev);
filp->private_data = devp;
spin_lock(&lock);
if (global_count) { //文件被打开
return -EBUSY;
}
global_count++;//增加使用计数器
spin_unlock(&lock);
/*判断文件打开的标志*/
return 0;
}
int global_mem_release(struct inode *inode, struct file *filp)
{
spin_lock(&lock);
global_count--;//减少使用计数器
spin_unlock(&lock);
return 0;
}