自旋锁

XWOS的自旋锁

概述

自旋锁是多核系统中为防止多个处理器同时访问公共的内存区域(称为临界区)而引入的一种锁。 当一个CPU获得自旋锁并访问临界区时,其他CPU只能 自旋 等待锁。 所谓 自旋 ,是指不断循环测试 是否已经解开。

自旋锁只是为SMP的场景设计的一种锁机制。在单核(UP)系统中,并不需要自旋锁。 但为了软件接口的统一,实现了虚假的自旋锁,只是对关闭抢占、中断底半部或中断的封装。

自旋锁还伴随其他操作:内存屏障,关闭调度器的抢占,关闭中断底半部,关闭中断等。

局限性

  • 自旋锁内包含内存内存屏障操作,内存屏障会降低CPU的性能;
  • 自旋锁不区分读和写的情况。

使用自旋锁

自旋锁的初始化

自旋锁是基于原子操作指令实现的,自旋锁结构体很小,核心数据是一个CPU指令能操作的基本数据类型,因此不提供动态创建和删除方法。 用户可以通过 xwos_splk_init() 初始化自旋锁。

多锁

当使用 多个 自旋锁保护临界区时,上锁和解锁顺序必须 保持一致 ,否则会导致死锁。

锁模式

  • 临界区只对 线程 上下文是安全的。临界区内,只会关闭抢占。 可以理解为在线程层面,临界区内的操作是 原子的 。临界区内的数据只能被 线程 上下文访问。 临界区内不能发生 调度 ,用户不可在临界区内使用会导致 睡眠阻塞 的CAPI。
        xwos_splk_lock(&lock);
        /* 临界区 */
        xwos_splk_unlock(&lock);
  • 临界区对 任意 上下文都是安全的。临界区内,不但会关闭抢占,还会把CPU中断也关了。 可以理解为在临界区内的操作是 原子的 ,临界区内的数据能被 任意 上下文访问。 临界区内不会发生中断,也不可能发生 调度 ,但用户依然不能在临界区内使用会导致 睡眠阻塞 的CAPI。
        xwos_splk_lock_cpuirq(&lock);
        /* 临界区 */
        xwos_splk_unlock_cpuirq(&lock);
  • 当使用 多个 自旋锁时,嵌套的临界区对 任意 上下文都是安全的。临界区内,不但会关闭抢占,还会把CPU中断也关了。 可以理解为在临界区内的操作是 原子的 ,临界区内的数据只能被 任意 上下文访问。 临界区内不会发生中断,也不可能发生 调度 ,但用户依然不能在临界区内使用会导致 睡眠阻塞 的CAPI。
        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(&lock, irq_array, num);
        /* 临界区 */
        xwos_splk_unlock_irqs(&lock, irq_array, num);
  • 当使用 多个 自旋锁时,嵌套的临界区对 线程指定的外设中断 是安全的。临界区内,只关闭抢占和指定的中断。 可以理解为在线程和指定的中断函数层面,临界区内的操作是 原子的 ,临界区内的数据只能被 线程指定的外设中断 上下文访问。 临界区内不会发生指定的中断,也不会发生 调度 ,但用户依然不能在临界区内使用会导致 睡眠阻塞 的CAPI。
        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(&lock);
        /* 临界区 */
        xwos_splk_unlock_bh(&lock);
  • 为什么没有 保存与恢复抢占保存与恢复中断底半部 形式的CAPI ? 因为 关闭与打开抢占保存与恢复中断底半部 是一种可重入的的 关闭 了多少次,对应的就要 打开 多少次。

CAPI参考