自旋锁
XWOS的自旋锁
Categories:
2 分钟阅读
概述
自旋锁是多核系统中为防止多个处理器同时访问公共的内存区域(称为临界区)而引入的一种锁。 当一个CPU获得自旋锁并访问临界区时,其他CPU只能 自旋 等待锁。 所谓 自旋 ,是指不断循环测试 锁 是否已经解开。
自旋锁只是为SMP的场景设计的一种锁机制。在单核(UP)系统中,并不需要自旋锁。 但为了软件接口的统一,实现了虚假的自旋锁,只是对关闭抢占、中断底半部或中断的封装。
自旋锁还伴随其他操作:内存屏障,关闭调度器的抢占,关闭中断底半部,关闭中断等。
局限性
- 自旋锁内包含内存内存屏障操作,内存屏障会降低CPU的性能;
- 自旋锁不区分读和写的情况。
使用自旋锁
自旋锁的初始化
自旋锁是基于原子操作指令实现的,自旋锁结构体很小,核心数据是一个CPU指令能操作的基本数据类型,因此不提供动态创建和删除方法。
用户可以通过 xwos_splk_init()
初始化自旋锁。
多锁
当使用 多个 自旋锁保护临界区时,上锁和解锁顺序必须 保持一致 ,否则会导致死锁。
锁模式
- 临界区只对 线程 上下文是安全的。临界区内,只会关闭抢占。
可以理解为在线程层面,临界区内的操作是 原子的 。临界区内的数据只能被 线程 上下文访问。
临界区内不能发生 调度 ,用户不可在临界区内使用会导致 睡眠 与 阻塞 的CAPI。
xwos_splk_lock()
:上锁,关闭抢占,进入临界区xwos_splk_trylock()
:尝试上锁,关闭抢占,尝试进入临界区xwos_splk_unlock()
:解锁,开启抢占,退出临界区
xwos_splk_lock(&lock);
/* 临界区 */
xwos_splk_unlock(&lock);
- 临界区对 任意 上下文都是安全的。临界区内,不但会关闭抢占,还会把CPU中断也关了。
可以理解为在临界区内的操作是 原子的 ,临界区内的数据能被 任意 上下文访问。
临界区内不会发生中断,也不可能发生 调度 ,但用户依然不能在临界区内使用会导致 睡眠 与 阻塞 的CAPI。
xwos_splk_lock_cpuirq()
:上锁,关闭抢占、CPU中断,进入临界区xwos_splk_trylock_cpuirq()
:尝试上锁,关闭抢占、CPU中断,尝试进入临界区xwos_splk_unlock_cpuirq()
:解锁,开启抢占、CPU中断,退出临界区
xwos_splk_lock_cpuirq(&lock);
/* 临界区 */
xwos_splk_unlock_cpuirq(&lock);
- 当使用 多个 自旋锁时,嵌套的临界区对 任意 上下文都是安全的。临界区内,不但会关闭抢占,还会把CPU中断也关了。
可以理解为在临界区内的操作是 原子的 ,临界区内的数据只能被 任意 上下文访问。
临界区内不会发生中断,也不可能发生 调度 ,但用户依然不能在临界区内使用会导致 睡眠 与 阻塞 的CAPI。
xwos_splk_lock_cpuirqsv()
:上锁,关闭抢占,保存CPU中断标志并关闭,进入临界区xwos_splk_trylock_cpuirqsv()
:尝试上锁,关闭抢占,保存CPU中断标志并关闭,尝试进入临界区xwos_splk_unlock_cpuirqrs()
:解锁,开启抢占,恢复CPU中断,退出临界区
xwos_splk_lock_cpuirqsv(&lock1, &cpuirq1);
/* 临界区1 */
xwos_splk_lock_cpuirqsv(&lock2, &cpuirq2);
/* 临界区2 */
xwos_splk_unlock_cpuirqrs(&loc2, cpuirq2);
/* 临界区1 */
xwos_splk_unlock_cpuirqrs(&loc1, cpuirq1);
- 临界区对 线程 、 指定的外设中断 是安全的。临界区内,只关闭抢占和指定的中断。
可以理解为在线程和指定的中断函数层面,临界区内的操作是 原子的 ,临界区内的数据只能被 线程 和 指定的外设中断 上下文访问。
临界区内不会发生指定的中断,也不会发生 调度 ,但用户依然不能在临界区内使用会导致 睡眠 与 阻塞 的CAPI。
xwos_splk_lock_irqs()
:上锁,关闭抢占,关闭部分中断,进入临界区xwos_splk_trylock_irqs()
:尝试上锁,关闭抢占,关闭部分中断,尝试进入临界区xwos_splk_unlock_irqs()
:解锁,开启抢占、开启部分中断,退出临界区
xwos_splk_lock_irqs(&lock, irq_array, num);
/* 临界区 */
xwos_splk_unlock_irqs(&lock, irq_array, num);
- 当使用 多个 自旋锁时,嵌套的临界区对 线程 、 指定的外设中断 是安全的。临界区内,只关闭抢占和指定的中断。
可以理解为在线程和指定的中断函数层面,临界区内的操作是 原子的 ,临界区内的数据只能被 线程 和 指定的外设中断 上下文访问。
临界区内不会发生指定的中断,也不会发生 调度 ,但用户依然不能在临界区内使用会导致 睡眠 与 阻塞 的CAPI。
xwos_splk_lock_irqssv()
:上锁,关闭抢占,保存部分中断标志并关闭,进入临界区xwos_splk_trylock_irqssv()
:尝试上锁,关闭抢占,保存部分中断标志并关闭,尝试进入临界区xwos_splk_unlock_irqsrs()
:解锁,开启抢占、恢复部分中断,退出临界区
xwos_splk_lock_irqssv(&lock1, irq_array, flag1_array, num);
/* 临界区1 */
xwos_splk_lock_irqssv(&lock2, irq_array, flag2_array, num);
/* 临界区2 */
xwos_splk_unlock_irqsrs(&lock2, irq_array, flag2_array, num);
/* 临界区1 */
xwos_splk_unlock_irqsrs(&lock1, irq_array, flag1_array, num);
- 临界区对 线程 、 中断底半部 是安全的。临界区内,只关闭抢占和中断底半部。
可以理解为在线程和中断底半部层面,临界区内的操作是 原子的 ,临界区内的数据只能被 线程 和 中断底半部 上下文访问。
临界区内不会发生 调度 ,但用户依然不能在临界区内使用会导致 睡眠 与 阻塞 的CAPI。
xwos_splk_lock_bh()
:上锁,关闭抢占、中断底半部,进入临界区xwos_splk_trylock_bh()
:尝试上锁,关闭抢占、中断底半部,尝试进入临界区xwos_splk_unlock_bh()
:解锁,开启抢占、中断底半部,退出临界区
xwos_splk_lock_bh(&lock);
/* 临界区 */
xwos_splk_unlock_bh(&lock);
- 为什么没有 保存与恢复抢占 和 保存与恢复中断底半部 形式的CAPI ? 因为 关闭与打开抢占 和 保存与恢复中断底半部 是一种可重入的的 锁 , 关闭 了多少次,对应的就要 打开 多少次。
CAPI参考
最后修改 September 22, 2021: chore: :tada: 创建工程 —— 玄武操作系统网站 (8c48765)