自旋锁的使用
自旋锁(spin_lock)是一种典型的对临界资源进行互斥访问的手段,顾名思义,为了获得一个自旋锁,在某CPU上运行的代码需要先执行一个原子操作,该操作测试并设置某个内存变量,在该操作完成之前其他执行单元不可能访问到这个内存变量。
如果测试结果表明锁已经空闲,则程序获得这个自旋锁并继续执行;如果测试表明锁仍被占用,程序将在一个小的循环内重复这个“测试并设置”操作,就是“自旋”的动作,就是原地打转。当自旋锁的持有者通过重置该变量释放这个自旋锁后,某个等待的“测试并设置”操作向其调用者报告锁已经释放。
Linux中自旋锁的操作
1. 定义自旋锁
spinlock_t lock;
2 初始化自旋锁
spin_lock_init(lock);
用于动态初始化自旋锁。
3. 获得自旋锁
spin_lock(lock);
该宏用于获得自旋锁lock,如果能够立即获得锁,马上返回,否则,它将自旋在那里直到锁被释放。
spin_trylock(lock);
尝试获得自旋锁lock,如果能后立即获得锁,返回真,否则立即返回假,也就是说不会再“原地打转”。
4. 释放自旋锁
spin_unlock(lock);
释放自旋锁lock,与lock和trylock配套使用。
5. 用法
//declear a spin lock spinlock_t lock; spin_lock_init(&lock); spin_lock(&lock); //获得自旋锁 ... //临界区 spin_unlock(&lock); //解锁
驱动工程师应谨慎使用,下面是需要注意的地方:
1. 自旋锁是忙等待,在得不到锁的时候会一直“测试并设置”,这样的话如果长时间得不到锁会浪费系统资源,所以适合用在等待时间比较短的情况下,不然会降低系统的性能。
2. 自旋锁可能会导致系统死锁。当2次试图获得这个自旋锁的时候,CPU会死锁。
3. 自旋锁锁定期间不能调用可能引起进程调度的函数,如果进程获得自旋锁之后再阻塞,如调用copy_from_user()、copy_to_user、kmalloc、msleep等函数,可能会导致内核崩溃。
下面举例说明使用自旋锁实现设备只能被一个进程打开。
我们还是沿用之前的globalmem的例子加以修改
int open_count = 0; //declear open times spinlock_t lock; int globalmem_open(struct inode *inode, struct file *filp) { spin_lock(&lock); if(open_count) { // already open printk(KERN_ERR "already open!\n"); spin_unlock(&lock); return -EBUSY; } open_count++; spin_unlock(&lock); printk(KERN_INFO "globalmem open!\n"); filp->private_data = globalmem_devp; return 0; } int globalmem_release(struct inode *inode ,struct file *filp) { spin_lock(&lock); open_count--; spin_unlock(&lock); printk(KERN_INFO "globalmem release!\n"); return 0; }
int globalmem_init(void) { int result; spin_lock_init(&lock);
jay@jay:/dev$ cat globalmem jay@jay:/dev$ echo "123" > globalmem jay@jay:/dev$ cat globalmem cat: globalmem: Device or resource busy jay@jay:/dev$ echo "123" > globalmem bash: globalmem: Device or resource busy jay@jay:/dev$
=========================================================
mail & MSN :[email protected]
=========================================================