rk3288 Linux锁的介绍

本文详细介绍了Linux内核中的锁机制,包括自旋锁和睡眠锁。自旋锁在无法获取时会循环等待,不进入休眠状态,如raw_spinlock_t和mutex。而睡眠锁在无法获取时会使当前线程休眠,如semaphore和rw_semaphore。文章还列举了各种锁的加锁、解锁函数及其用途,并探讨了信号量与互斥锁的区别。最后,给出了不同上下文环境下选择锁类型的指导原则。
摘要由CSDN通过智能技术生成

参考资料:

https://www.kernel.org/doc/html/latest/locking/index.html
https://mirrors.edge.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/

锁的类型

Linux内核提供了很多类型的锁,它们可以分为两类

  • 自旋锁(Spinning locks)
  • 睡眠锁(Sleeping locks)

自旋锁类型

简单地说就是无法获得锁时,不会休眠,会一直循环等待,有这些自旋锁:

自旋锁描述
raw_spinlock_t原始自旋锁
bit spinlocks位自旋锁

自旋锁加锁、解锁函数是:spin_lock、spin_unlock,还可以加上各种后缀,后缀表示加锁和解锁会做额外地事:

后缀描述
_bh()加锁时禁止下半部(软中断),解锁时使能下半部(软中断)
_irq()加锁时禁止中断,解锁时使能中断
_irqsave/restore()加锁时禁止并记录状态,解锁时恢复中断位所记录的状态

睡眠锁类型

睡眠锁无法获得锁时,会将当前线程休眠。

休眠锁描述
mutexmutual exclusion,彼此排斥,即互斥锁(后面讲解)
rt_mutex
semaphore信号量、旗语
rw_semaphore读写信号量,读写互斥,但是可以多人同时读
ww_mutex
precpu_rw_semaphore对rw_semaphore的改进,性能更优

自旋锁具体实现

spinlock函数在内核文件include\linux\spinlock.h中声明,如下表:

休眠锁描述
spin_lock_init(_lock)初始化自旋锁为unlock状态
void spin_lock(spinlock_t *lock)获取自旋锁(加锁),返回后肯定获得了锁
int spin_trylock(spinlock_t *lock)尝试获得自旋锁,成功获得锁则返回1,否则返回0
void spin_unlock(spinlock_t *lock)释放自旋锁,或称解锁
int spin_is_locked(spinlock_t *lock)返回自旋锁的状态,已加锁返回1,否则返回0

自旋锁的加锁、解锁函数是:spin_lock、spin_unlock,还可以加上各种后缀,这表示在加锁或加锁的同时,还会做额外的事情。

信号量semaphore

semaphore函数在内核文件include\linux\semaphore.h中声明,如下表:

函数名作用
DEFINE_SEMAPHORE(name)定义一个struct semaphore name结构体,count值设置为1
void sema_init(struct semaphore *sem, int val)初始化semaphore
int down_interruptible(struct semaphore *sem)获得信号量,如果暂时无法获得就会休眠,
休眠过程有可能受到信号而被唤醒,要判断返回值:
0:获得了信号量
-EINTER:被信号量打断
int down_killable(struct semaphore *sem)跟down_interruptible类似,down_interruptible 可以被任意信号唤醒,
但down_killable只能被"final signal"唤醒,返回值:
0:获得了信号量
-EINTR:被信号打断
int down_trylock(struct semaphore *sam)尝试获得信号量,不会休眠,返回值:
0:获得了信号量
1:没能获得信号量
int down_timeout(struct semaphore *sem, long jiffies)获得信号量,如果不成功,休眠一段时间返回值:
0:获得了信号量
-ETIME:这段时间内没能获取信号量,超时返回down_timeout休眠过程中,他不会被信号唤醒
void up(struct semaphore *sem)释放信号量,唤醒其他等待信号量的进程

互斥量mutext

mutex函数在内核文件include\linux\mutext.h中声明,如下表:

函数名作用
mutex_init(mutex)初始化一个struct mutext指针
DEFINE_MUTEX(mutexname)初始化struct mutex mutexname
int mutex_is_locked(struct mutex *lock)获得mutex,如果暂时无法获得,休眠
返回之时必定是已经获得了mutex
int mutex_lock_interruptible(struct mutex *lock)获得mutex,如果暂时无法获得,休眠
休眠过程中可以被信号唤醒,返回值:
0:成功获得了mutex
-EINTR:被信号唤醒了
int mutex_lock_killable(struct mutex *lock)跟mutex_lock_interruptible类似,mutex_lock_interruptible可以被任意信号唤醒,但mutex_lock_killable只能被"fatal signal"唤醒,返回值:
0:获得了mutex
-EINTR:被信号打断
int mutex_trylock(struct mutex *lock)尝试获取mutex,如果无法获得,不会休眠,返回值:
1:获得了mutex
0:没有获得
注意,这个返回值含义跟一般的mutex函数相反
void mutex_unlock(struct mutex *lock)释放mutex,会唤醒其他等待同一个mutex的线程
int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock)让原子变量的值减1,如果减1后等于0,则获取mutex,返回值:
1:原子变量等于0并且获得了mutex
0:原子变量减1后并不等于0,没有获得mutex

semaphore和mutex区别

semaphore和mutex是不是只是资源个数的区别呢,如果semaphore设置为1,那是不是和mutex一样了呢?

struct mutex {
    /* 1: unlocked, 0: locked, negative: locked, possible waiters */
    atomic_t        count;
    spinlock_t      wait_lock;
    struct list_head    wait_list;
#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_MUTEX_SPIN_ON_OWNER)
    struct task_struct  *owner;									//指向某个线程,只能由加锁的此线程来解锁
#endif
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
    struct optimistic_spin_queue osq; /* Spinner MCS lock */
#endif
#ifdef CONFIG_DEBUG_MUTEXES
    void            *magic;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
    struct lockdep_map  dep_map;
#endif
};
  • 一个mutex只能在进程上下文中使用,谁给mutex加锁,就只能由谁来解锁。
  • sempahore没有这个限制,可以用来解决“读写”问题,A在等待数据获取锁,B产生数据释放锁,释放的同时唤醒A读取数据。(没有进程限定)

何时用何种锁

本节参考:https://wenku.baidu.com/view/26adb3f5f61fb7360b4c656e.html
英文原文:https://mirrors.edge.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/

/IRQ Handler AIRQ Handler BSoftirq ASoftirq BTasklet ATasklet BTimer ATimer BUser Context AUser Context B
IRQ Handler ANone
IRQ Handler Bspin_lock_irqsave()None
Softirq Aspin_lock_irq()spin_lock_irq()spin_lock()
Softirq Bspin_lock_irq()spin_lock_irq()spin_lock()spin_lock()
Tasklet Aspin_lock_irq()spin_lock_irq()spin_lock()spin_lock()None
Tasklet Bspin_lock_irq()spin_lock_irq()spin_lock()spin_lock()spin_lock()None
Timer Aspin_lock_irq()spin_lock_irq()spin_lock()spin_lock()spin_lock()spin_lock()None
Timer Bspin_lock_irq()spin_lock_irq()spin_lock()spin_lock()spin_lock()spin_lock()spin_lock()None
User Context Aspin_lock_irq()spin_lock_irq()spin_lock_bh()spin_lock_bh()spin_lock_bh()spin_lock_bh()spin_lock_bh()spin_lock_bh()None
User Context Bspin_lock_irq()spin_lock_irq()spin_lock_bh()spin_lock_bh()spin_lock_bh()spin_lock_bh()spin_lock_bh()spin_lock_bh()down_interruptible()None

使用场景

本节参考:https://wenku.baidu.com/view/26adb3f5f61fb7360b4c656e.html
英文原文:https://mirrors.edge.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

习惯就好zz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值