• linux多处理器并发访问共享资源---自旋锁


    自旋锁spinlock是专为防止多处理器并发而引入的一种锁,它在内核中大量应用于中断处理等部分(对于单处理器来说,防止中断处理中的并发可简单采用关闭中断的方式,即在标志寄存器中关闭/打开中断标志位,不需要自旋锁)。

    何谓自旋锁?它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁"自旋"一词就是因此而得名。自旋锁在锁定的时候,如果不成功,不会睡眠,会持续的尝试,cpu的时候自旋锁会让其它process动不了。

    使用不好容易导致死锁。

    自旋锁的效率远高于互斥锁自旋锁比较适用于锁使用者保持锁时间比较短的情况。正是由于自旋锁使用者一般保持锁时间非常短。

    信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此只能在进程上下文使用,而自旋锁适合于保持时间非常短的情况,不止可在进程上下文使用,也可在中断上下文使用。

    自旋锁适合于保持时间非常短的情况,它可以在任何上下文使用。如果被保护的共享资源只在进程上下文访问,使用信号量保护该共享资源非常合适,如果对共享资源的访问时间非常短,自旋锁也可以。但是如果被保护的共享资源需要在中断上下文访问,就必须使用自旋锁

    自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠

    自旋锁一直占用CPU,他在未获得锁的情况下,一直运行

    在用自旋锁时有可能造成死锁,当递归调用时有可能造成死锁,调用有些其他函数也可能造成死锁,如 copy_to_user()copy_from_user()kmalloc()等。

    因此我们要慎重使用自旋锁,自旋锁只有在内核可抢占式或SMP的情况下才真正需要,在单CPU且不可抢占式的内核下,自旋锁的操作为空操作。自旋锁适用于锁使用者保持锁时间比较短的情况下。

    spin_lock如果能够立即获得锁,就会马上返回,否则它将在原地打转,直到该锁持有者释放,而spin_trylock如果立即获得锁,则返回true,若没有获得,也会立即返回false。

    使用自旋锁后,可以保证临界区(共享资源)不受本CPU和别的CPU进程抢占的影响,但是还有可能受到中断和底半部(bottom half)的影响,所以若中断也要访问临界区资源,则需要用到以下函数

    spin_lock_irq() = spin_lock() + local_irq_disable() //禁止本地中断,并获取自旋锁
    spin_unlock_irq() = spin_unlock() + local_irq_enable() //激活本地中断,并释放自旋锁
    spin_lock_irqsave() = spin_lock() + local_irq_save() //保存中断状态,禁止本地中断,并获取自旋锁
    spin_unlock_irqrestore() = spin_unlock() + local_irq_restore() //将中断状态恢复到以前的状态,并且激活本地中断,释放自旋锁
    spin_lock_bh() = spin_lock() + local_bh_disable() //禁止底半部中断,并获取自旋锁
    spin_unlock_bh() = spin_unlock() + local_bh_enable() //激活底半部中断,并释放自旋锁
     

    在进程上下文中调用spin_lock_irqsave(flags)和spin_unlock_irqrestore(flags),中断上下文中调用spin_lock()和spin_unlock(),这样一来可以避免一切核间并发的可能性,并同时也避免和一切核内并发的可能性。

    使用自旋锁应注意以下几个问题:

    由于自旋锁属于忙等待的方式,所以自旋锁适用于临界区耗时很小的情况,如果临界区很大,使用自旋锁会非常耗费CPU性能
    同一个CPU递归使用自旋锁会造成死锁,这一点跟互斥锁是一样的
    在自旋锁锁定期间不能调用可能引起
    进程调度的函数,或者引起阻塞的函数,比如copy_to_user()、copy_from_user()、kmalloc()、msleep()等等函数,因为自旋锁上锁期间会禁止抢占,无法执行调度,所以会造成内核崩溃
    由于spin_lock_irqsave并不能屏蔽别的CPU中断,所以进程上下文调用了spin_lock_irqsave和spin_unlock_irqrestore,中断里最好也调用spin_lock和spin_unlock

     

  • 相关阅读:
    【广州华锐互动】3D景区实景导航,让旅行加更加舒适轻松
    深度学习(18):RuntimeWarning: overflow encountered in exp学习笔记
    HTML学生个人网站作业设计:游戏网站设计——原神首页 1页 带轮播图
    nginx代理参数proxy_pass
    MySQL支持哪些存储引擎
    SpringBoot的starter到底是什么?
    GeoAO:一种快速的环境光遮蔽方案
    Java反射(Reflex)机制
    基于Java+SpringBoot+Mybaties-plus+Vue+ElementUI 失物招领小程序 设计与实现
    Django 里获取url里的参数
  • 原文地址:https://blog.csdn.net/FPGASOPC/article/details/132907479