您的位置:首页 > 运维架构 > Linux

Linux 设备驱动 ====> 并发控制 --- 自旋锁

2017-05-31 20:23 218 查看
自旋锁的使用

自旋锁(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. 用法

[cpp]
view plain
copy

print?

//declear a spin lock  
spinlock_t lock;  
spin_lock_init(&lock);  
  
spin_lock(&lock);        //获得自旋锁  
...                      //临界区  
spin_unlock(&lock);      //解锁  



//declear a spin lock
spinlock_t lock;
spin_lock_init(&lock);

spin_lock(&lock);        //获得自旋锁
...                      //临界区
spin_unlock(&lock);      //解锁


自旋锁主要用于SMP或者单CPU内核抢占的情况下使用。

驱动工程师应谨慎使用,下面是需要注意的地方:

1. 自旋锁是忙等待,在得不到锁的时候会一直“测试并设置”,这样的话如果长时间得不到锁会浪费系统资源,所以适合用在等待时间比较短的情况下,不然会降低系统的性能。

2. 自旋锁可能会导致系统死锁。当2次试图获得这个自旋锁的时候,CPU会死锁。

3. 自旋锁锁定期间不能调用可能引起进程调度的函数,如果进程获得自旋锁之后再阻塞,如调用copy_from_user()、copy_to_user、kmalloc、msleep等函数,可能会导致内核崩溃。

下面举例说明使用自旋锁实现设备只能被一个进程打开。

我们还是沿用之前的globalmem的例子加以修改

[cpp]
view plain
copy

print?

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 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;
}


在init函数中初始化

[cpp]
view plain
copy

print?

int globalmem_init(void)  
{  
    int result;  
    spin_lock_init(&lock);  



int globalmem_init(void)
{
int result;
spin_lock_init(&lock);


然后我们重新编译并添加模块,然后使用上篇中的测试app来测试,当我们运行测试程序的时候,马上再去打开globalmem的时候会提示设备忙。

[plain]
view plain
copy

print?

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$   



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 :zhangjie201412@live.com

=========================================================
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: