对于Mutex互斥锁,其同一时间只能被一个线程所占有,其它申请该锁的线程会进入阻塞休眠态,让出CPU时间片。
其一般使用在临界区逻辑较长的程序中,使得多线程互斥的访问临界资源。而Linux中引入自旋锁主要是解决多处理器
对内核数据结构的互斥访问。确保其访问的原子性,基本流程为:锁定=》操作=》解锁
自旋锁其功能和互斥锁类似,目的是保护一小段临界区的原子性,其本质为一个原子变量atomic,主要包含两种状态:
- locked
- unlocked
当一个任务希望执行访问临界资源的临界区时,需要检查这个锁是否处于Unlocked解锁状态。
若自旋锁正处于Locked锁定状态,当前线程会一直自旋:不断的检查锁是否可用,即处于忙等待过程。占用CPU时间片。
①其相较于互斥锁优缺点?
互斥锁在锁不可用时,会进入阻塞态,让出CPU,而自旋锁会处于忙等待,避免上下文切换,
因此其适用于临界区较短的程序中。
②为什么需要引入自旋锁?
解决多处理器情形(SMP体系)下互斥进入临界区的问题。
两个线程的任务分别运行在不同的CPU上,那么它们将无法做到互斥进入临界区。
自旋锁:
确保在不同CPU上执行的线程只有一个可以获取该互斥结构,从而确保多核下访问临界区的互斥性。
其结构spinlock的内容为:
typedef struct spinlock
{
union
{
struct raw_spinlock rlock;
};
}spinlock_t;
typedef struct raw_spinlock
{
arch_spinlock_t raw_lock;
}raw_spinlock_t;
typedef struct qspinlock
{
atomic_t val;
}arch_spinlock_t;
可以看到 spinlock在X86-64体系下,本质是一个atomic原子变量。
【自旋锁的死锁问题】
首先关于中断:
中断:外部事件发生时,中断控制器通知CPU,CPU切换到中断处理程序上下文,进行外部事件处理。
①中断造成死锁
Linux SpinLock解决思路:进入临界区时,禁止中断,从而避免切换到中断上下文。
抢占:高优先级的任务抢占正在执行的低优先级的任务,从而获得CPU使用劝。
②同一个CPU上抢占造成死锁
多个进程上下文运行在同一个CPU上,当高优先级任务抢占了正在执行的低优先级任务,而低优先级任务正处于临界区。
Linux SpinLock解决思路:进入临界区时,禁止抢占。
由此可见,自旋锁其主要特点是:
- 主要是为了解决多个CPU体系下,小段临界区的保护。
- 由于互斥锁的忙等待特性,其容易引起死锁。解决思路是进入临界区时禁止中断或抢占