• LINUX内核笔记:自旋锁


    目录
     
    1、自旋锁作用与基本使用方法?
    与其他锁一样,自旋锁也用于保护临界区,但是自旋锁主要是用于在SMP上保护临界区。在SMP上,自旋锁最多只能被一个可执行线程持有,如果一个线程尝试获得一个被争用的自旋锁,该线程将一直旋转(while循环)直到锁可用;如果锁未被争用,请求锁的执行线程将立刻争用它,并继续执行。
     
    LINUX下自旋锁的基本使用方法:
    声明锁:
    spinlock_t lock;
     
    初始化:
    lock = SPIN_LOCK_UNLOCKED;
         或者
    spin_lock_init(&lock);
     
    加锁有4个接口,3个会阻塞,1个不阻塞
    spin_lock(&lock);//获取自旋锁
    spin_lock_irq(&lock);//关中断,获取自旋锁,不建议使用
    spin_lock_irqsave(&lock, flags);//关中断,保存中断状态,获取自旋锁
    spin_trylock(&lock);//与spin_lock一样,但是获取不到的时候不阻塞,返回非0
     
    对应的解锁接口有3个
    spin_unlock(&lock);//spin_lock和spin_trylock都用该接口解锁
    spin_unlock_irq(&lock);//不建议使用
    spin_unlock_irqrestore(&lock, flags);
     
    另外还提供了一个获取锁状态的接口:
    spin_is_locked(&lock);//如果指定的锁被获取,返回非0,否则,返回0
     
    2、在SMP和UP上的不同表现?
    对于SMP,自旋锁将在禁止抢占后,while循环自旋直到锁可用;
    对于UP,自旋锁的行为有点不一样,具体表现为:
    • 内核不支持抢占,则spin_lock是个空函数,spin_unlock也是空函数;
    • 内核支持抢占,则spin_lock关抢占,spin_unlock开抢占。
    要分析SMP和UP的区别,还得先理解UP下内核支持抢占与否的区分。
    在不支持抢占的时候,内核调度时机为:
    • 内核代码一直要执行到完成(返回用户空间);
    • 阻塞或主动调用schedule();
    支持内核抢占的内核,则在以下情况会发生抢占:
    • 从中断处理程序回到内核空间且内核具有抢占性时;
    • 当内核代码再一次具有可抢占性时;(如时钟中断,发现进程时间片已经用完,则发生进程抢占)
    • 内核显式调用schedule();
    • 内核中的任务阻塞(同样导致schedule());
    从以上区别可以看出,若是内核不支持抢占,只要临界区的代码不阻塞,就能保证原子性,所以spin_lock/spin_unlock是空函数。
    而对于支持抢占的内核, spin_lock/spin_unlock自然只需要关闭/恢复抢占功能即可。
     
     
    3、自旋锁与上下文
    由于自旋锁不睡眠,既可以用于进程上下文,也可用于非进程上下文,这是它与信号量相比的一个优势。
    正常来讲,如果自旋锁都是在进程上下文中使用,则建议使用spin_lock/spin_unlock。
    若在中断处理例程中也要使用自旋锁,则所有争用同一个锁的地方应使用spin_lock_irqsave/spin_unlock_irqrestore。
    若没有在中断而在下半部使用自旋锁,则所有急用同一个锁的地方可以使用spin_lock_bh/spin_unlock_bh,这对函数平时用得比较少。
    注:自旋锁用在中断例程中,若是进程上下文中的内核代码使用spin_lock,则在临界区,可能发生中断 ,要么原子性被破坏(UP),要么造成死锁(SMP).
     
    4、使用spin_lock()后为什么不能睡眠?
    在UP下,正如前面所说,原子性得不到保证。
    而在SMP下,则可能发生死锁:
    假设有3个进程A,B,C,2个CPU称CPU0,CPU1.
    CPU0上A进程获取自旋锁进入睡眠,调度了B进程,B进程将自旋; 
    CPU1上调度了C进程也将自旋。
    B等着A释放锁,A等着B释放CPU,自旋后的CPU不能发生调度,CPU0和CPU1将一直自旋下去,形成了死锁。
     
     
    5、强调:锁什么?
    使用锁的时候一定要对症下药,明确保护的是数据而不是代码,这是使用锁的正确思考方式。经常看别人代码的人应该会有所体会,针对代码加锁常常使代码难以理解,特别是复杂的程序,往往加锁没做好,引起竞争条件。
    不防在使用锁的时候先思考一下自己要保护什么,然后给对应的锁取跟数据相关的名称。比如"int foo;spinlock_t foo_lock;"表示foo由foo_lock加锁;
     
    6、参考
    《Linux内核设计与实现》
  • 相关阅读:
    Eclipse部署项目到Tomcat中,class文件夹为空的解决方案
    微软(北京).NET俱乐部活动 (2010年6月26日) – Visual Studio 2010 /*LIFE RUNS ON CODE*/
    失望的Vista SP1
    急聘BI DW OLAP开发工程师 (北京)
    急聘.NET开发工程师 (北京)
    开篇
    Windows Vista User Account Control (UAC) 全新安全模块“用户帐户控制”
    Tidy your desktop
    [导入]Vista的屏幕截图小工具:Snipping Tool
    微软发布官方TFS 2010 Scrum 模板
  • 原文地址:https://www.cnblogs.com/pheye/p/3629587.html
Copyright © 2020-2023  润新知