spinlock与中断、抢占的关系

在kernel中,一个线程获得了spinlock,那么这个线程可以被interrupt吗?

可以,spin_lock 并没有关中断,只关闭了抢占,spin_lock_irqsave,spin_lock_irq,spin_lock_bh等才关中断了,这些是在spin_lock可能会被中断上下文拥有时使用的模式。


tips1:为什么要关闭抢占?

static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock) { unsigned long flags; local_irq_save(flags); preempt_disable(); spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); 。。。


      关闭抢占是在所有spin_lock中都会做的,下面阐述禁止抢占的原因:

如果不禁止内核抢断(或者不禁止中断),可能会有以下的情况发生(假设进程B比进程A具有更高的优先级):

进程A获得spinlock lock

进程B运行(抢占进程A)

进程B获取spinlock lock

由于进程B比进程A优先级高,所以进程B在进程A之前运行,而进程B需要进程A释放lock之后才能运行,于是,死锁



tip2:在关闭本地中断后是否有必要关闭抢占?

    前阵子有网友发短消息问:“...在研究自旋锁的时候,发现在 spin_lock_irq函数,也就是在自旋锁中关闭中的这类函数中,既然已经关闭了本地中断,再禁止抢占有没有多余。也就是说,既然本地中断已经禁止了,在本处理器上是无法被打断的,本地调度器也无法运行,也就不可以被本地调度程序调度出去..."

从spinlock设计原理看,使用它的时候,在临界区间是务必确保不会发生进程切换。现在的问题是,如果已经关闭了中断,在同一处理器上如果不关掉内核抢占的特性,会不会有进程调度的情况发生,如果没有,那我个人的理解是,在local_irq_disable之后再使用peempt_disable就多此一举了。

这个在SMP系统上最好理解了,假设有A和B两个处理器,使用spin lock的进程(简称"焦点进程"好了)运行在处理器A上,一种很明显的情形就是如果有个进程(简称“睡眠进程”好了)先于焦点运行,但是因为等待网卡的一个数据包,它进入了sleep状态,然后焦点开始被调度运行,后者在spin lock获得锁后进入临界区,此时网卡收到了"睡眠进程“的数据包,因为焦点只是关闭了A上的中断,所以B还是会接收并处理该中断,然后唤醒“睡眠进程“,后者进入运行队列,此时出现一个调度点,如果”睡眠“的优先级高于”焦点“,那么就有进程切换发生了,但是如果焦点所使用的spin lock中关闭了内核抢占,那么就使得先前的进程切换成为不可能。

     如果是在单处理器系统上,local_irq_disable实际上关闭了所有(其实就一个)处理器的中断,所有有中断引起的调度点都不可能存在,此时有无其他与中断无关的调度点出现呢?在2.4上,因为没有抢占,这种情形绝无可能,事实上,早期的内核很大程度上是依赖local_irq_disable来做资源保护,这个看看2.4的内核源码就很清楚了,里面有大量的对local_irq_disable函数的直接调用。

     2.6有了抢占的概念,local_irq_save等函数只是禁止了本地中断,即当前CPU上的中断。在单核CPU上,当然抢占就不可能发生了,但是在多核CPU上由于其他核上的中断并没有被禁止,是仍然可能发生抢占的,但本CPU内不会被抢占。UP下关闭中断,如前所述,实际上已经杜绝了内部因素导致的“就绪队列中加入一个进程”这个调度点的可能(内部因素实际上只剩下了一个处理器的异常,但是关中断的情形下,即便有异常也不会导致进程的切换),因此到这里我们可以这样说,在UP上关闭中断情形下,preempt_disable其实是多余的。但是我们知道,spin lock是一种内核API,不只是kernel的开发者在用,更多的内核模块(.ko,实际当中更多地表现形式是设备驱动程序)开发者也在使用。内核的设计者总是试图将其不能控的代码(所谓的外部因素了)可能给内核带来的损失降低至最小的程度,这个表现在内核对中断处理框架的设计时尤其明显,所以在UP系统下先后使用local_disable_irq和preempt_disable,只是尽量让你我可能在spin lock/unlock的临界区中某些混了头的代码不至于给系统带来灾难,因为难保某些人不会在spin lock的临界区中,比如去wake_up_interruptible()一个进程,而被唤醒的进程在可抢占的系统里就是一个打开的潘多拉盒子。

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值