Linux---自旋锁spinlock、信号量semaphore、互斥锁mutex介绍及各自对应使用场景

一、Linux 锁的介绍

Linux中按照大类分为2种锁,睡眠锁和自旋锁。其中睡眠锁就是无法获得锁的时候,当前线程进入休眠状态,包括信号量semaphore、互斥锁mutex。自旋锁就是当无法获得锁时,不会休眠,一直循环等待,只有一种spinlock。

自旋锁 spinlock

spinlock 函数在内核文件 include\linux\spinlock.h 中声明,如下表
自旋锁相关函数

信号量 semaphore

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

函数名作用
DEFINE_SEMAPHORE(name)定义一个 struct semaphore name 结构体, count 值设置为 1
void sema_init(struct semaphore *sem, int val)初始化 semaphore
void down(struct semaphore *sem)获得信号量,如果暂时无法获得就会休眠返回之后就表示肯定获得了信号量在休眠过程中无法被唤醒,即使有信号发给这个进程也不处理
int down_trylock(struct semaphore *sem)尝试获得信号量,不会休眠,返回值:0:获得了信号量 1:没能获得信号量
void up(struct semaphore *sem)释放信号量,唤醒其他等待信号量的进程

互斥锁 mutex

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

函数名作用
mutex_init(mutex)初始化一个 struct mutex 指针
DEFINE_MUTEX(mutexname)初始化 struct mutex mutexname
int mutex_is_locked(struct mutex *lock)判断 mutex 的状态1:被锁了(locked)0:没有被锁
void mutex_lock(struct mutex *lock)获得 mutex,如果暂时无法获得,休眠返回之时必定是已经获得了 mutex
int mutex_trylock(struct mutex *lock)尝试获取 mutex,如果无法获得,不会休眠,返回值:1:获得了 mutex,0:没有获得注意,这个返回值含义跟一般的 mutex 函数相反
void mutex_unlock(struct mutex *lock)释放 mutex,会唤醒其他等待同一个 mutex 的线程

semaphore和mutex的区别

区别
强调一下: mutex 只能在进程上下文中使用,谁给 mutex 加锁,就只能由谁来解锁。semaphore 的锁定与释放,并不限定为同一个进程。

二、各种锁的使用场景

如下图是各个场景下锁的使用:
在这里插入图片描述
以上图红色圈为例,介绍下怎么看这张表,红圈表示如果“ IRQ Handler A”和“ Softirq A”要竞争临界资源,那么需要使用“spin_lock_irq()”函数。为什么不能用 spin_lock 而要用 spin_lock_irq?也就是为什么要把中断给关掉?假设在 Softirq A 中获得了临界资源,这时发生了 IRQ A 中断, IRQ Handler A 去尝试获得自旋锁,这就会导致死锁,所以需要关中断。

针对各个场景如上图,我们总结一下
1、假设只有程序 A、程序 B 会抢占资源,这 2 个程序都是可以休眠的,所以可以使用信号量。

2、在用户上下文与 Softirqs 之间加锁,可以使用 spin_lock_bh 函数,它会先禁止本地 CPU 的中断下半部即 Softirq。

3、在用户上下文与 Tasklet 之间加锁,同“在用户上下文与 Softirqs 之间加锁”完全一样。

4、在用户上下文与 Timer 之间加锁,同“在用户上下文与 Softirqs 之间加锁”完全一样。

5、在 Tasklet 与 Timer 之间加锁,可以使用 spin_lock()、spin_unlock()来保护临界资源。不需要用 spin_lock_bh(),因为一旦当前 CPU 已经处于 Tasklet 或 Timer中,同一个 CPU 不会同时再执行其他 Tasklet 或 Timer。

6、在 Softirq 之间加锁,可以使用 spin_lock()、 spin_unlock()来访问临界区,原因同上。

7、硬件中断服务例程与一个 Softirq共享数据,在 Softirq 获得锁之前,禁止当前 CPU 的中断;在硬件中断服务例程中不需要使用 spin_lock_irq(),因为当它在执行的时间 Softirq 是不可能执行的,它可以使用 spin_lock()用来防止别的 CPU 抢占。

8、硬件中断 A、硬件中断 B 都要访问临界资源,使用 spin_lock()实现互斥访问临界资源就可以了。因为 Linux 不支持中断嵌套,即当前 CPU 正在处理中断 A 时,中断 B 不可能在当前 CPU 上被处理,不需要再次去禁止中断。

9、spin_lock用于阻止在不同CPU上的执行单元对共享资源的同时访问以及不同进程上下文互相抢占导致的对共享资源的非同步访问,而中断失效和软中断失效却是为了阻止在同一CPU上软中断或中断对共享资源的非同步访问。

本文主要摘录自韦东山韦老师的《嵌入式Linux应用开发完全手册_韦东山全系列视频文档全集V2.8》百问网嵌入式资料下载

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux中的spinlock是一种自旋锁机制,用于保护对共享资源的访问,以防止同时访问导致的数据竞争问题。spinlock使用了一种称为自旋的技术,即当一个线程需要获取锁时,它会一直等待,直到锁被释放。这种等待是循环的,即线程会不断地检查锁的状态,直到锁被释放为止。 spinlock相比于传统的互斥量(mutex)和信号量semaphore)等锁机制,具有更高的性能和灵活性。spinlock不需要使用内核调度器,因此不会产生额外的上下文切换开销。此外,spinlock可以用于任何需要保护的临界区代码,而不仅仅是用于进程之间的同步。 使用spinlock时,需要将其初始化为0,以便其他线程可以安全地访问共享资源。当一个线程需要获取锁时,它可以使用spin_lock函数来锁定spinlock。如果锁已经被其他线程占用,该线程将进入自旋状态,不断检查锁的状态。当该线程获取到锁时,它可以将共享资源置于临界区并执行相关操作。在操作完成后,该线程可以使用spin_unlock函数释放锁。 spinlock机制适用于一些简单的同步场景,例如在并发访问共享资源时保护临界区代码。然而,对于一些复杂的同步需求,可能需要使用更高级的同步机制,如读写锁(rwlock)或条件变量(condition variable)。 总之,spinlock是一种轻量级的自旋锁机制,适用于简单的同步场景,具有较高的性能和灵活性。它适用于任何需要保护的临界区代码,而不仅仅是用于进程之间的同步。在使用spinlock时,需要注意避免死锁和过度自旋等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值