一、介绍
自旋锁,当加锁不成功时,自旋,自旋锁会不断的占用CPU进行变量的测试,由于属于原子操作,所以该CPU的占用会升为100%,所以,使用自旋锁时,临界区的代码需要很短,否则会影响系统性能,此外,作为锁机制的一种,使用自旋锁同样需要注意死锁的出现,自旋锁锁定期间不能调用可能引起进程调度的函数,如果进程获得自旋锁之后再阻塞,eg,copy_from_user(),copy_to_user(),kmalloc(),msleep()等,一旦阻塞发生就可能导致内核 崩溃
二、函数介绍
比较\类型 传统自旋锁 读写自旋锁 顺序锁 RCU机制
应用场合 需要上锁者独占的资源 需要写者独占的资源 很少同时读写的资源 读多写少的资源
读+读 并发 × √ √ √
读+写 并发 × × √ √
写+写 并发 × × × √
流程
抢锁-操作-解锁
示例
int cnt=0;
lock_t lock;
static int my_open()
{
lock(&lock);
if(cnt){
unlock(&lock)
}
cnt++;
unlock(&lock);
}
static int release()
{
lock(&lock);
cnt--;
unlock(&lock);
传统自旋锁
锁定的临界区域不允许其他CPU访问,仍然会被中断和底半部的影响
将自旋锁+中断屏蔽来防止使用自旋锁访问临界资源的时候被中断打断
//定义并初始化自旋锁
spinlock_t spinlock
void spin_lock_init(spinlock_t *);
//加锁
//spin_lock - 加锁函数(忙等)
void spin_lock(spinlock_t *lock);
int spin_trylock(spinlock_t *lock);
spin_lock_irq(); //=spin_lock() + local_irq_disable()
spin_lock_irqsave(); //= spin_lock() + lock_irq_save();
spin_lock_bh(); //=spin_lock() + local_bh_disable();
//解锁
void spin_unlock(spinlock_t *lock);
spin_unlock_irq(); //=spin_unlock() + local_irq_enable()
spin_unlock_irqrestore(); //= spin_unlock() + lock_irq_restore();
spin_unlock_bh(); //=spin_unlock() + local_bh_enable();
static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, RET_IP);
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}
static inline void __raw_spin_lock_irq(raw_spinlock_t *lock)
{
local_irq_disable();
preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, RET_IP);
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}
spin_lock_irq 禁止本地中断
读写自旋锁
允许多个CPU同时读临界资源,不允许同时写资源
读者 + 读者 不互斥
读者 + 写者 互斥
写者 + 写者 互斥
//include/linux/rwlock.h
//定义并初始化自旋锁
rwlock_t rwlock;
void rwlock_init(rwlock_t *lock);
//加读锁
void read_lock(rwlock_t *lock);
int read_trylock(rwlock_t *lock);
void read_lock_irqsave(rwlock_t *lock,unsigned long flags);
void read_lock_irq(rwlock_t *lock, unsigned long flags);
void read_lock_bh(rwlock_t *lock);
//解读锁
void read_unlock(rwlock_t *lock)
void read_unlock_irqrestrore(rwlock_t *lock,unsigned long flags);
void read_unlock_irq(rwlock_t *lock, unsigned long flags);
void read_unlock_bh(rwlock_t *lock);
//加写锁
void write_lock(rwlock_t *lock)
int write_trylock(rwlock_t *lock)
void write_lock_irqsave(rwlock_t *lock,unsigned long flags);
void write_lock_irq(rwlock_t *lock, unsigned long flags);
void write_lock_bh(rwlock_t *lock);
//解写锁
void write_unlock(rwlock_t *lock)
void write_unlock_irqrestrore(rwlock_t *lock,unsigned long flags);
void write_unlock_irq(rwlock_t *lock, unsigned long flags);
void write_unlock_bh(rwlock_t *lock);
顺序锁
读写锁的升级版,允许写者和读者同时访问临界区,临界区不能有指针
读者 + 读者 不互斥
读者 + 写者 不互斥 , 临界区没有指针+读者需自己注意更新
写者 + 写者 互斥
//include/linux/seqlock.h
//定义顺序锁
struct seqlock_t sl;
//获取顺序锁
void write_seqlock(seqlock_t *sl);
void write_tryseqlock(seqlock_t *sl);
void write_seqlock_irqsave(lock,flags); //=local_irq_save() + write_seqlock()
void write_seqlock_irq(seqlock_t *sl); //=local_irq_disable() + write_seqlock()
void write_seqlock_bh(seqlock_t *sl); //local_bh_disable() + write_seqlock()
//释放顺序锁
void write_sequnlock(seqlock_t *sl);
void write_sequnlock_irqsave(lock,flags); //=local_irq_restore() + write_sequnlock()
void write_sequnlock_irq(seqlock_t *sl); //=local_irq_enable() + write_sequnlock()
void write_sequnlock_bh(seqlock_t *sl); //local_bh_enable() + write_sequnlock()
//读开始
unsigned read_seqbegin(const seqlock_t *sl);
read_seqbegin_irqsave(lock,flags); //=local_irq_save() + read_seqbegin();
//重读
int read_seqretry(const seqlock_t *sl,unsigned iv);
read_seqretry_irqrestore(lock,iv,flags); //=local_irq_restore() + read_seqretry();