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互斥体
概述
一个进程访问临界资源之前先获取互斥体,如果获取不到,进程不能访问临界资源,此时进程切换到休眠状态文章来源:https://www.toymoban.com/news/detail-622393.html
特点
- 申请不到互斥体的进程切换到休眠状态,休眠状态不消耗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原子操作
概述
将进程访问临界资源的过程看作一个不可分割的原子状态。当进程访问完临界资源后,原子状态被打破。另一个进程可以访问临界资源,原子操作是通过对原子变量的数值修改来实现的,原子变量数值的修改又依赖于内联汇编实现。文章来源地址https://www.toymoban.com/news/detail-622393.html
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
到了这里,关于linux内核中竞态的解决方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!