Linux内核的并发与同步

1、简介

1.1 基本概念

抢占式内核: 用户程序在执行系统调用期间可以被高优
先级进程抢占
非抢占式内核:用户程序执行系统调用不能被其他进程
抢占

对称多处理器(SMP): 一个计算机上汇集了多个处理
器,他们共享内存和总线,可并行处理数据
单处理器: 只有一个CPU

并发指的是多个执行单元同时、并行被执行,而并发的执行单元对共享资源(硬件资源和软件上的全局变量、静态变量等)的访问则很容易导致竞态。
当多个进程、线程或中断同时访问同一个资源,可能导致错误。

2 原子变量

共享资源恰巧是一个简单的整数值,普通整数的加减操作不能保证在多线程下的原子操作,使用锁机制代价又太高,所以出现了原子操作。

2.2 主要方法
//定义原子变量,两种方法
atomic_t n = ATOMIC_INIT(0);
void atomic_set(atomic_t *v, int i);
//读原子变量的值
void atomic_read(atomic_t *v);
//原子变量加、减i值
void atomic_add(int i, atomic_t *v);
void atomic_sub(int i, atomic_t *v);
//原子变量加、减1
void atomic_inc(atomic_t *v);
void atomic_dec(atomic_t *v);

3、信号量

linux内核中的信号量是一种资源锁,进程只有得到该锁(信号量)才能执行临界区代码,执行完毕释放该锁
信号量采用睡眠等待机制:如果有一个任务试图获得一个已经被占用的信号量时,信号量会将其推到一个等待队列中睡眠,当持有信号量的进程将信号量释放后,处于等待队列中的那个任务被唤醒,并将获得该信号量。
中断服务函数不能进行睡眠,因此信号量不能用于中断当中,但可以使用后面介绍的自旋锁

3.1 使用流程

1、定义一个信号量
2、初始化信号量
3、获得信号量(减操作)
==>执行临界区代码
4、释放信号量(加操作)

3.2 主要方法
#include <linux/semaphore.h>//信号量相关函数的头文件
//定义一个信号量
struct semaphore my_sem;
//初始化信号量
void sema_init(struct semaphore *sem, int val);
参数1:信号量变量
参数2:信号量的计数值
//获取信号量(减操作,不能被系统消息打断,导致调用者睡眠)
void down(struct semaphore *sem);
//获取信号量(减操作,可以被系统消息打断,导致调用者睡眠)
int down_interruptible(struct semaphore *sem);
//尝试获得信号量,成功返回0,失败返回非0,不会导致调用者睡眠
int down_trylock(struct semaphore *sem);
//释放信号量,即使信号量加1(如果线程睡眠,将其唤醒)
void up(struct semaphore *sem);

4、互斥体

互斥体与信号量类似,不过更简单,只有加锁、解锁两种状态

4.1 主要方法
//定义锁变量
struct mutex my_mutex;
//初始化锁
mutex_init(struct mutex *lock);
//加锁,如果加锁不成功,会阻塞当前进程
void mutex_lock(struct mutex *lock);
//解锁
void mutex_unlock(struct mutex *lock);
//尝试加锁,会立即返回,不会阻塞进程
int mutex_trylock(struct mutex *lock);

5、自旋锁

自旋锁的名称源于它的工作原理:尝试获取一个自旋锁,如果锁空闲就获取该自旋锁并继续向下执行;如果锁已被占用就循环检测该锁是否被释放( 原地打转直到锁被释放)
 只有在占用锁的时间极短的情况下使用;不能递归使用一个自旋锁(形成死锁);占用锁时不能使用可能引起进程调度的函数,如copy_xx_user()、kmalloc()、msleep()…
自旋锁主要针对SMP或单CPU抢占内核的情况,而对于单CPU非抢占内核自旋锁退化为空操作

5.1 主要方法
#include <linux/spinlock.h>
//定义自旋锁变量
struct spinlock my_spinlock;
spinlock_t my_spinlock;
//自旋锁初始化
spin_lock_init(&my_spinlock); 
//获得自旋锁(可自旋等待,可被软、硬件中断)
void spin_lock(spinlock_t *my_spinlock);
//释放自旋锁,退出临界区
void spin_unlock(spinlock_t *lock)
//尝试获得自旋锁(不自旋等待,成功返回1、失败则返回0)
int spin_trylock(spinlock_t *lock)

自旋锁变体

//获得自旋锁(可自旋等待,保存中断状态并关闭软、硬件中断)
void spin_lock_irqsave(spinlock_t *my_spinlock,unsigned long flags);
//释放自旋锁,退出临界区
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值