zoukankan      html  css  js  c++  java
  • Linux内核同步

      并发的执行单元对共享资源(硬件资源,软件上的全局变量、静态变量)的访问很容易导致竞态,避免竞态的方法:

    1、中断屏蔽

      在进入临界区之前屏蔽系统的中断,但是在驱动编程中不值得推荐,驱动通常需要考虑跨平台特点而不假定自己在单核上运行。中断对于内核的运行非常重要,在屏蔽中断期间所有的中断都无法处理,长时间屏蔽中断会造成数据丢失或者系统崩溃。local_irq_disable和local_irq_enable都只能禁止和使能本CPU的中断,在SMP系统中并不能解决多CPU引发的竞态。单独使用中断屏蔽不推荐使用,适合和下文的自旋锁联合使用。

    2、原子操作

      原子操作可以保证对一个整形数据的修改是排他性的,Linux内核提供了很多函数来实现内核中的原子操作,这些函数又分为对位和整形变量的原子操作,它们都依赖于底层CPU的原子操作,因此,这些函数都是和CPU的架构相关的。

    3、自旋锁

      自旋锁是一种典型的对临界资源进行互斥访问的手段,为了获得一个自旋锁,在CPU上执行的代码先执行一个原子操作,该操作测试并设置某个内存变量,由于该操作时原子操作,在它完成之前其他执行单元不可能访问这个内存变量。如果测试结果表明这个锁已经空闲,则程序获得这个锁,并继续执行,如果锁被占用,则程序在一个小循环内重复执行这个“测试并设置”操作,这也是自旋锁的由来。

      自旋锁主要针对SMP或者单CPU但内核可抢占的情况,对于单CPU和内核不支持抢占的系统,自旋锁退化为空操作。在单CPU和内核可抢占的系统中,自旋锁持有期间,内核的抢占将被禁止。由于内核可抢占的单CPU系统的行为实际上很类似与SMP系统,因此,在这样的单CPU系统中使用自旋锁很有必要。另外,在多核SMP的情况下,任何一个核拿到自旋锁,这个核上的抢占也被禁止了,但是没有禁止另外一个核的抢占调度。

      在多核编程的时候如果进程和中断可能访问同一片临界资源,我们一般需要在进程的上下文中调用spin_lock_irqsave / spin_unlock_irqrestore,在中断上下文调用spin_lock / spin_unlock,这样,在CPU0上,无论是进程上下文还是中断上下文获得了自旋锁,此后,如果CPU1无论是进程上下文还是中断上下文,想获得同一个自旋锁都必须忙等待,这避免一切核间并发的可能性。同时,由于每个核的进程上下文持有锁的时候用的是spin_lock_irqsave,所以该核上的中断时不可能进入的,这避免了核内并发的可能性。

      进程不能获得自旋锁时会忙等待,十分耗费CPU,因此只有临界区非常小的时候采用自旋锁。

      自旋锁还包括读写自旋锁、顺序锁。

    4、RCU(读-复制-更新)

    5、信号量

      信号量适合用于临界区比较长的情况,当一个进程不能获得信号量时,就会在这个信号量上睡眠,直到有其他进程释放信号量将这个进程唤醒。信号量的值可以是0,1或者n。

    6、互斥量

      信号量已经可以实现互斥的功能,但是,正宗的mutex在Linux内核中还是存在的。互斥量和自旋锁属于不同层次的互斥手段,前者依赖于后者,在互斥量本身的实现上,为了保证互斥量结构存取的原子性,需要自旋锁来互斥,所以自旋锁属于更底层的手段。互斥量适合于进程占用资源较长的情况,互斥量会引起进程睡眠。互斥量所保护的临界区可能包含引起阻塞的代码,而自旋锁不能用来保护包含可能引起阻塞的代码的临界区。因为阻塞意味着进程的切换,如果进程被切换出去,另一个进程企图获得本自旋锁,死锁就会发生。

      因为spin_lock中会使用preempt_disable()关闭抢占,spin_unlock会重新开启抢占功能。从这里面可以看出,使用自旋锁保护的区域是工作在非抢占状态,即使获取不到锁,在“自旋”状态也是禁止抢占的。到这里,大概可以理解为什么自旋锁保护的代码不能睡眠了。如果在自旋锁保护的代码中睡眠,此时发生进程调度,则可能另外一个进程会再次调用spin_lock保护这段代码,而我们知道,即使在获取不到锁的自旋状态,也是禁止抢占的,而“自旋”又是动态的,不会在睡眠了,也就是说在这个处理器上不会再有调度发生了,那么死锁自然就发生了。

      如果被保护的资源需要在中断或者软中断情况下使用,则在互斥量和自旋锁之间只能选择自旋锁,当然,如果一定要使用互斥量,则只能通过mutex_trylock方式进行,不能获取就立即返回避免阻塞。

     7、完成量

      Linux定义了完成量,它用于一个执行单元等待另一个执行单元完成某事。

      

  • 相关阅读:
    【MySQL疑难杂症】如何将树形结构存储在数据库中(方案二 Path Enumeration)
    【MySQL疑难杂症】如何将树形结构存储在数据库中(方案一 Adjacency List)
    【Java疑难杂症】利用Java核心库实现简单的AOP
    【Java入门提高篇】Day5 Java中的回调(二)
    【Java入门提高篇】Day4 Java中的回调
    【SpringMVC】使用Myeclipse创建SpringMVC项目【超详细教程】
    使用GDAL/OGR读写矢量文件
    WebGL简易教程(四):颜色
    WebGL简易教程(三):绘制一个三角形(缓冲区对象)
    OSG与Shader的结合使用
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9307640.html
Copyright © 2011-2022 走看看