自旋锁和互斥锁实例_并发与竞态 (自旋锁)

简介

自旋锁: 它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。----百度百科

由以上介绍大概了解,自旋锁就是内核为防止临界区被多个进程同时访问出错的一种机制。其作用是保证临界区在任一时刻有且仅有一个进程访问。

应用场景

举个例子:
app1: 向驱动设备(/dev/driver_case)写入1024个字节的'a'字符,然后读取,25s后再次读取;
app2: 向驱动设备(/dev/driver_case)写入1024个字节的'b'字符,然后读取,25s后再次读取;
驱动设备:注册驱动/dev/driver_case。将app写入的数据存入到内核空间,并在app读取时打印出来。

问题:两个app都会占用驱动25s,如果先执行app1占用驱动,在app1没有结束占用之前,再执行app_2占用了驱动,会出现什么后果?现象:

abf7e850d5b6266bec9d2739789c0606.png

第一次访问.png

e4e5341d3c08b04c80392f93bf9cbb03.png

第二次访问.png

分析:第一次读取时,发现app1写入的是‘a’,app2写入的是‘b’。但是第二次读取时,发现app1写入的值被app2覆盖掉了,这就会出现问题了。

解决方法:驱动引入自旋锁,在驱动被一个进程占用没有释放之前,不允许其他进程占用。

实例分析

1.声明自旋锁结构体变量

#include 
……
struct driver_case_dev {
……
#ifdef SPINLOCK_SUPPORT
spinlock_t lock;
#endif
};

struct driver_case_dev driver_case;

2.初始化自旋锁

……
spin_lock_init(&driver_case.lock);
……

3.入口设计

static int driver_case_open(struct inode *inode, struct file *filp)
{
#ifdef SPINLOCK_SUPPORT
unsigned long flags;

spin_lock_irqsave(&driver_case.lock, flags);
if (driver_case.dev_status) {
spin_unlock_irqrestore(&driver_case.lock, flags);
return -EBUSY;
}
driver_case.dev_status++;
spin_unlock_irqrestore(&driver_case.lock, flags);
#endif
……

return 0;
}

4.出口设计

static int driver_case_release(struct inode *inode, struct file *filp)
{
#ifdef SPINLOCK_SUPPORT
unsigned long flags;

spin_lock_irqsave(&driver_case.lock, flags);
if (driver_case.dev_status) {
driver_case.dev_status--;
}
spin_unlock_irqrestore(&driver_case.lock, flags);
#endif
……
return 0;
}

注意:需要注意的是,这里自旋锁保护的临界区是driver_case.dev_status增减操作。驱动通过判断driver_case.dev_status的值来确定当前驱动是否被占用。
这里的例子效果不是很明显,理想的是在open入口直接给上一个自旋锁,然后在release出口函数释放。但是自旋锁的缺点是在整个持锁过程中,会导致访问的进程阻塞,且本例期间会屏蔽中断。由于app占用时间25s,会导致期间中断不会响应,且进程长时间阻塞。因此没有按照理想情况设计,driver_case.dev_status增减操作执行很快,不会导致以上问题出现,因此选用此种方案。

测试

2966fe0db1af1ab0cb7f7ccab4d57d10.png

测试图.png

由上可知,在执行第一个app时,是正常运行的。此时再执行第二个app时,会发现无法访问驱动。从而避免驱动在被占用期间,再次被其他进程访问的问题了。

记录历经的路,分享个人总结与感悟。关注“开源519”公众号,聊天窗口发送 “自旋锁” 获取本篇代码实例,更多驱动学习资料尽在“开源519”公众号。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值