一、同步互斥机制
应用场景:多线程的时候。当多个执行单元同时被执行,处理的是同一个资源时,就会导致竞态,这个时候就需要用同步或者互斥的方法来解决竞态。
线程和进程的区别:进程是拥有资源的最小单位,线程是参与调度的最小单位。
执行单元:进程、线程、SMP(对称多处理器)
资源:软件资源或者是硬件资源
并发:多个执行单元同时被执行。
竞态:多个执行单元同时被执行,处理的是同一个资源,就会导致竞态。
临界区:对资源进程操作的代码区
临界资源:可能会被多个执行单元同时访问并操作的资源
-
导致竞态原因:
1.多进程同时访问操作临界资源(进程和抢占它的进程之间会导致竞态) 2.进程和中断 3.对称多处理器
-
解决竞态的方法:
同步:强调的是顺序性 互斥:强调的是排他性
-
具体的解决方法:
1.屏蔽中断 2.自旋锁 3.原子操作 4.互斥体(互斥锁) 5.信号量
二、自旋锁
头文件:linux/spinlock.h
自旋锁数据类型:spinlock_t
锁机制,完成互斥操作,和互斥锁类似
上自旋锁;
临界区;
解自旋锁;
自旋锁上锁后,会屏蔽掉进程抢占,如果进程1在临界区出现进程调度的相关函数(例如:sleep),就相当于放弃了CPU的执行权。这时,操作系统就会去调度其他进程(进程2),进程2在执行的时候需要进行上锁,但是进程1还没有释放锁,进程2就获取不到锁,会进入自旋状态,导致CPU会被100%占用。如果CPU是单核的,sleep函数结束后,进程1由于进程2(进入自旋状态)把CPU资源全部占用,解锁永远不会执行,就会导致死锁。
注意:尤其是在单核CPU的情况下,不能够在自旋锁保护的临界区出现关于进程调度相关函数。
- 相关函数:
需要定义一个flag标志位,用来判断是否为第一次打开
spin_lock_init(spinlock_t *lock)
功能:初始化自旋锁
参数:
@lock 自旋锁结构体指针
void spin_lock(spinlock_t *lock)
功能:自旋锁上锁
参数:
@lock 自旋锁结构体指针
int spin_trylock(spinlock_t *lock)
功能:自旋锁上锁
参数:
@lock 自旋锁结构体指针
特点:如果上锁失败,错误返回
void spin_unlock(spinlock_t *lock)
功能:自旋锁解锁
参数:
@lock 自旋锁结构体指针
自旋锁的初始化:
自旋锁的上锁与解锁:
标志位的定义及加减操作函数:
运行结果:
三、互斥体
头文件: <linux/mutex.h>
数据类型: struct mutex
互斥体上锁
临界区
互斥体解锁
- 相关函数:
mutex_init(struct mutex *mutex)
功能:初始化互斥体
参数:
@mutex 互斥体结构体指针
void mutex_lock(struct mutex *lock)
功能:互斥体上锁
参数:
@lock 互斥体结构体指针
特点:互斥体上锁失败,会导致应用层进程休眠
void mutex_unlock(struct mutex *lock)
功能:互斥体解锁
参数:
@lock 互斥体结构体指针
互斥体的上锁和解锁:
运行结果: