关于自旋锁spinlock的一些理解

    这里并不是讲spinlock的一般用法,只是提出自己曾经的一些疑问点,也给出自己的解答。
    在《LINUX内核设计与实现》《LINUX设备驱动程序》里都提过,在非抢占式的单处理器系统上的自旋锁被优化为不做任何事情。我最初的疑问是即使是单处理器,没有抢占能力,但时间片用完,持有锁的一方终会交出锁,等待锁的一方不会永远自旋下去。但在《linux设备驱动程序》里面明确说到,“如果非抢占式的单处理器系统进入某个锁上的自旋状态,则会永远自旋下去;也就是说,没有任何其他线程能够获得CPU来释放这个锁”。
    为了说明问题,还是有必要先说明一下在SMP(多处理器)或抢占式下就需要真正的自旋锁。
    一、SMP下
    CPU A对公共资源执行一些操作,在这个过程中随时CPU B也可以对公共资源执行操作。
    如下面的代码片断:
    if (NULL == buf)
        buf = kmalloc(size, GFP_KERNEL);
    当CPU A,CPU B都执行了if (NULL == buf),发现buf的确为NULL,那么都会进行内存分配,但是只有一个可以被buf记录(最后执行赋值那个)。这样会造成另一部内存无法回到系统。
    所以SMP上,需要锁实现。
    二、抢占式
    在2.4及以前的linux内核均不是抢占式内核,是在2.6正式引入的。按以前的进程调度,如果一个进程在不耗光自己时间片前,不主动退出是不会交出控制权的,很明显这样一些实时性要求很高的进程无法得到满足,所以需要抢占。
    如下图所示,进程A即使被中断打断了,后面还是会回到进程A,但进程B可能更需要马上执行,如用户敲了一个字符。


    如果是抢占式,在中断后进程调度器可以调度更高优先级的进程执行,如下所示:
   

    从上面可以看出,进程A可能随时会被B所抢占,即是在单处理器上也会造成SMP同样的并发问题,所以需要锁实现。
    有了上面的介绍后,我们回到原来的问题:在非抢占式的单处理器系统上的自旋锁被优化为不做任何事情。
    
    
   

    上面是linux2.6.10的非SMP下spinlock的内核代码,虽然非抢占也调用了preempt_disable();(禁用内核抢占),但进去后会发现非抢占定义为#define preempt_disable()        do { } while (0)
     spinlock最初就是为多处理器系统设计的。这里有一条很重要的原则,上面两本书都没有提到过,那就是不能在可能交出CPU控制权的代码上运行,被调度,休眠都不可以。
    内核从2.6开始就支持内核抢占,对于非内核抢占系统,内核代码可以一直执行,直到完成,也就是说当进程处于内核态时,是不能被抢占的(当然,运行于内核态的进程可以主动放弃CPU,比如,在系统调用服务例程中,由于内核代码由于等待资源而放弃CPU,这种情况叫做计划性进程切换(planned process switch))。但是,对于由异步事件(比如中断)引起的进程切换,抢占式内核与非抢占式是有区别的,对于前者叫做强制性进程切换(forced process switch)。 那么单处理器非抢占内核下,内核进程是可以不主动交出CPU的。
    在中断使用spinlock,如果其他中断可能使用你的保护区域,那么可以禁止本地中断,即同一CPU的中断。那为什么不用禁止其他CPU的中断呢,假使另一CPU尝试持有锁而自旋,但由于是不同CPU,所以持有锁的CPU总会执行完,所以不会永远自旋下去。但是本地中断打断后自旋,那么将无法恢复,因为持有锁的代码永远没有机会释放锁。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值