linux内核中竞态的解决方法

1、内核中竞态的产生原因

表面原因

  • 多个进程同时访问同一个驱动资源时,造成了资源的争抢,这个就是竞态

本质原因

  • 对于单核处理器,支持资源抢占,那么就会出现竞态
  • 对于多核处理器,核与核之间本身就会存在竞态
  • 对于中断和进程,也存在竞态
  • 中断和中断之间,如果支持中断嵌套(一个中断正在执行,另一个优先级高的中断来了),那么就会出现竞态,不支持中断嵌套则没有竞态

2、竞态的解决方法

2.1中断屏蔽

概述

对于单核处理器,中断和进程会产生竞态,为了解决这个竞态,可以在进程访问临界资源时让中断不启用。但是如果长时间不启用中断就会对整个系统产生不利的影响,严重是甚至会导致系统崩溃。所以使用中断屏蔽时要求屏蔽中断的时间尽可能短。(NS),中断屏蔽一般是内核开发者进行调试时使用。

API

//屏蔽中断
local_irq_disable();
临界资源
//中断使能
local_irq_enable();

2.2自旋锁(盲等锁)

概述

内核专门为多核CPU设计

一个进程访问临界资源时使用自旋锁对进程上锁,另一个进程也想访问,但是解不开锁,此时这个进程进入自旋状态(盲等状态)

特点

  • 处于自旋状态下的进程是运行态,需要消耗CPU资源
  • 自旋锁锁住的临界资源要求临界资源的体积小,而且临界资源中不可以有延时、耗时甚至休眠的操作,也不可以有copy_to_user()和copy_from_user()
  • 自旋锁会出现死锁
  • 自旋锁可以用于进程访问临界资源时,也可以用于中断访问临界资源
  • 自旋锁上锁后会关闭抢占

API

//定义一个自旋锁
spinlock_t lock;
//初始化自旋锁
spin_lock_init(&lock);  
//上锁
void spin_lock(spinlock_t *lock)
//解锁
void spin_unlock(spinlock_t *lock)

2.3信号量

概述

进程在访问临界资源之前先去申请信号量,如果申请到了就访问,申请不到,此时进程切换到休眠状态

特点

  • 申请不到信号量的进程切换到休眠状态,休眠状态不消耗CPU资源,但是状态切换的过程需要消耗CPU资源
  • 信号量保护的临界区可以很大,里面也可以有延时、耗时甚至休眠的操作
  • 信号量只能用于进程上下文,不能用于中断上下文
  • 信号量不会出现死锁
  • 信号量也不会关闭抢占

API

1.定义信号量
struct semaphore sema;
2.初始化信号量
void sema_init(struct semaphore *sem, int val)
参数:
sem:定义的信号量首地址
val:初始化信号量数值,这里初始化为1
返回值:无
3.void down(struct semaphore *sem);
功能:申请信号量

4.void up(struct semaphore *sem);
功能:释放信号量

2.4互斥体

概述

一个进程访问临界资源之前先获取互斥体,如果获取不到,进程不能访问临界资源,此时进程切换到休眠状态

特点

  • 申请不到互斥体的进程切换到休眠状态,休眠状态不消耗CPU资源,但是状态切换的过程需要消耗CPU资源
  • 互斥体保护的临界区可以很大,里面也可以有延时、耗时甚至休眠的操作
  • 互斥体只能用于进程上下文,不能用于中断上下文
  • 互斥体不会出现死锁
  • 互斥体也不会关闭抢占
  • 和信号量不同的是,如果将进程获取不到互斥体,进程不会立即进入休眠,而是等待一段时间,这个时间期间如果获取到互斥体,进程可以不用休眠。所以互斥体的效率要比信号量高

API

1.定义互斥体
struct mutex mutex;
2.初始化互斥体
mutex_init(&mutex);
3.获取互斥体
void mutex_lock(struct mutex *lock);
4.释放互斥体
void mutex_unlock(struct mutex *lock);

2.5原子操作

概述

将进程访问临界资源的过程看作一个不可分割的原子状态。当进程访问完临界资源后,原子状态被打破。另一个进程可以访问临界资源,原子操作是通过对原子变量的数值修改来实现的,原子变量数值的修改又依赖于内联汇编实现。

API

1.定义原子变量并初始化
atmoic_t atm=ATOMIC_INIT(1);//解决竞态时只有1和-1两种值;除这俩之外还有计时的作用
2.
int atomic_dec_and_test(atomic_t *v)
功能:原子变量的数值-1并且拿结果和0比较
参数:
    v:原子变量的首地址
返回值:
如果原子变量数值-1后结果为0,则返回真,否则返回假

3.void atomic_inc(atomic_t *v)
功能:原子变量的数值+1
************************************
1.定义原子变量并初始化
atmoic_t atm=ATOMIC_INIT(-1);
2.
int atomic_inc_and_test(atomic_t *v)
功能:原子变量的数值+1并且拿结果和0比较
参数:
    v:原子变量的首地址
返回值:
如果原子变量数值+1后结果为0,则返回真,否则返回假

3.void atomic_dec(atomic_t *v)
功能:原子变量的数值-1
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值