- 自旋锁的几点说明
- 与信号量不同, 自旋锁可在不能休眠的代阿中使用, 比如中断处理例程
- 一个自旋锁就是一个互斥设备, 只有两个状态: 锁定 和 解锁
- 自旋锁是某个整数值的单个位, 希望获得锁的进程需测试相关位
- 锁可用, 则"锁定"位被设置, 进程进入临界区
- 锁不可用, 则进程进入忙循环, 重复检查该锁, 直到可用为止
- 测试和设置 的操作必须以原子方式进行
- 自旋锁 API 介绍
- 结构实现
- <linux/spinlock.h>
- 锁的类型: spinlock_t
- 初始化
- 静态初始化
- spinlock_t my_lock = SPIN_LOCK_UNLOCKED;
- 动态初始化
- void spin_lock_init(spinlock_t *lock);
- 静态初始化
- 操作
- 说明
- 所有自旋锁等待在本质上都是不可中断的, 一旦调用spin_lock, 在获得锁之前一直处于自旋
- 获取锁操作
- void spin_lock(spinlock_t *lock);
- 释放锁操作
- void spin_unlock(spinlock_t *lock);
- 说明
- 结构实现
- 使用锁的基本规则
- 拥有自旋锁的代码是原子的, 不能休眠
- 不能因为任何原因放弃处理器
- 中断除外
- 在编写自旋锁下执行的代码时, 要注意任何一个函数, 保证不会休眠
- 在拥有自旋锁时需要禁止中断(仅在本地CPU)
- 自旋锁需要在尽可能短的时间内拥有
- 拥有自旋锁的代码是原子的, 不能休眠
- 自旋锁函数
- 锁定自旋锁函数
-
void spin_lock(spinlock_t *lock);
- 获得自旋锁
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
- 在获得自旋锁前禁止中断(在本地CPU), 中断状态保存在 flags中
void spin_lock_irq(spinlock_t *lock);
- 在释放自旋锁时启用中断, 不需要跟踪标志
void spin_lock_bh(spinlock_t *lock);
- 在获得锁之前禁止软中断, 保持硬中断打开
如果自旋锁可以被中断(包括软/硬中断)中的代码获得, 我们需要禁止中断;如果锁不会在硬中断中获得, 却可能在软中断中获得, 那么应该使用 spin_lock_bh, 这样即使锁死, 也可以响应硬中断.
-
- 释放自旋锁函数
- void spin_unlock(spinlock_t *lock);
- void spin_unlock_irqsave(spinlock_t *lock, unsigned long flags);
- 需要与 spin_lock_irqsave 在同一函数中调用
- void spin_unlock_irq(spinlock_t *lock);
- void spin_unlock_bh(spinlock_t *lock);
- 非阻塞的自旋锁操作
- 说明: 这俩个函数在成功时返回非零值, 否则返回零值
- int spin_trylock(spinlock_t *lock);
- int spin_trylock_bh(spinlock_t *lock);
- 锁定自旋锁函数
- 读取者/写入者自旋
- 介绍及代码实现
- 类似于 读取写入信号量, 可以允许多个读取者, 只有一个写入者
- <linux/spinlock.h>
- 类型: rwlock_t
- 声明和初始化
-
静态方式: rwlock_t my_rwlock = FW_LOCK_UNLOCKED;
动态方式:
rwlock_t my_rwlock;
rwlock_init(&my_rwlock);
-
- 读取者函数
- 获得锁
- void read_lock(rwlock_t *lock);
- void read_lock_irqsave(rwlock_t *lock,unsigned long flags);
- void read_lock_irq(rwlock_t *lock);
- void read_lock_bh(rwlock_t *lock);
- 释放锁
- void read_unlock(rwlock_t *lock);
- void read_unlock_irqsave(rwlock_t *lock,unsigned long flags);
- void read_unlock_irq(rwlock_t *lock);
- void read_unlock_bh(rwlock_t *lock);
- 获得锁
- 写入者函数
- 获得锁
- void write_lock(rwlock_t *lock);
- void write_lock_irqsave(rwlock_t *lock,unsigned long flags);
- void write_lock_irq(rwlock_t *lock);
- void write_lock_bh(rwlock_t *lock);
- void write_trylock(rwlock_t *lock);
- 释放锁
- void write_unlock(rwlock_t *lock);
- void write_unlock_irqsave(rwlock_t *lock,unsigned long flags);
- void write_unlock_irq(rwlock_t *lock);
- void write_unlock_bh(rwlock_t *lock);
- 获得锁
- 介绍及代码实现
- 锁陷阱
- 不明确规则
- 控制访问的锁应该在可并发对象创建时就定义
- 信号量和自旋锁都不允许二次获得锁
- 内部函数可以(或者需要)假定已经获得锁, 但提供外部的函数必须显式处理锁
- 锁的顺序调用
- 当多个进程需要同时获得多个锁时, 进程需要按照相同的顺序获得锁
- 在信号量和自旋锁组合使用时, 需要先获得信号量, 再获得自旋锁
- 不明确规则
- 细粒度和粗粒度
- 通常规则, 应该在最初使用粗粒度, 真正的性能约束一般出现在非预期情况下
- 工具 lockmeter 可以度量锁花费的时间
linux 驱动编程___竞态/并发问题___自旋锁
最新推荐文章于 2024-09-16 20:17:55 发布