Linux 自旋锁

自旋锁的核心思想:

设置一个在多处理器之间共享的全局变量锁L,并定义当L=1时为上锁状态,L=0位解锁状态。如果处理器A上的代码要进入临界区,它要先读取L的值,判断其是否为0,如果L!=0表明有其他处理器上的代码正在对共享数据进行访问,此时处理器A进入忙等待即自旋状态,如果L=0表明当前没有其他处理器上的代码进入临界区,此时处理器A可以访问该资源,它先把L置1,然后进入临界区,访问完毕离开临界区时将L置0.

static inline void spin_lock(spinlock_t *lock)

{

raw_spin_lock(&lock->rlock);

}

static inline void raw_spin_lock(raw_spinlock_t *lock)

{

preempt_disable(); //关闭调度器

do_raw_spin_lock(lock);//加锁操作

}

do_raw_spin_lock()函数可以保证原子的去判断和更改自旋锁的值,具体可参看源码。

以下场景会遇到问题:

一个进程正在占用自旋锁L,此时产生了中断,并且中断中对自旋锁L进行了获取操作,这样将导致死锁。

遇到上述情况需要用到spin_lock_irq锁

static inline void spin_lock_irq(spinlock_t *lock)

{

raw_spin_lock_irq(&lock->rlock);

}

static inline void raw_spin_lock_irq(raw_spinlock_t *lock)

{

local_irq_disable();//关闭中断

preempt_disable();//关闭调度器

do_raw_spin_lock(lock);//加锁操作

}

spin_lock_irq与spin_lock的区别就是关闭中了中断,从而解决了上面的问题。

spin_lock_irq存在的问题,就是当遇到smp系统的时候,此时关闭的中断只是关闭当前进程所在的cpu上面的中断,其他cpu上面依然会产生中断。如果其他cpu上面产生了中断并且试图去获取自旋锁,这样中断函数中依然会自旋,但是进程所在的cpu上面依然可以运行,所以不会导致死锁的发生。这个问题就需要我们在自旋锁的临界区内的代码必须是原子的,不能休眠。

spin_lock_irqsave()与spin_lock_irq的区别,在关闭中断前会将处理器当前的FLAGS寄存器的值保存在一个变量中,spin_unlock_irqrestore()来释放锁。

void spin_lock_bh(spinlock_t *lock);相对于spin_lock_irq,该函数用来处理软中断。void spin_unlock_bh用来释放锁。

非阻塞版本:

static inline int spin_trylock(spinlock_t *lock);

static inline int spin_trylock_irq(spinlock_t *lock);

spin_trylock_irqsave(lock, flags);

spin_trylock_bh(spinlock_t *lock);

这些非阻塞版本的自旋锁函数在试图获得一个锁时,如果发现该锁处于上锁状态,会直接返回0而不是自旋,如果成功则返回1.

读写自旋锁rwlock

与之前的spin_lock类比起来,这种锁比较有意思的地方在于:它允许任意数量的读取者同时进入临界区,但写入者必须进行互斥访问。一个进程想进去读的话,必须检查是否有进程在写,有的话必须自旋,否则可以获得锁。一个进程想进去写的话,必须先检查是否有进程正在读或写,有的话必须自旋。

rwlock版本:

对于读取者:

void read_lock(rwlock *lock);

void read_lock_irq(rwlock_t *lock);

void read_lock_irqsave(rwlock_t *lock, unsigned long flags);

void read_unlock(rwlock_t *lock);

void read_unlock_irq(rwlock_t  *lock);

void read_unlock_irqrestore(rwlock_t *lock, unsigned long flags);

对于写入者:

void write_lock(rwlock_t *lock);

void write_lock_irq(rwlock_t *lock);

void write_lock_irqsave(rwlock_t *lock, unsigned long flags);

void write_unlock(rwlock_t *lock);

void write_unlock_irq(rwlock *lock);

void write_unlock_irqrestore(rwlock_t *lock, unsigned long flags);

try版本:

int read_trylock(rwlock *lock);

int write_trylock(rwlock_t *lock);


已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页