自旋锁spin_lock和raw_spin_lock
自旋锁spin_lock和raw_spin_lock
Linux内核spin_lock、spin_lock_irq 和 spin_lock_irqsave 分析
http://blog.csdn.net/droidphone/article/details/7395983
本文不打算详细探究spin_lock的详细实现机制,只是最近对raw_spin_lock的出现比较困扰,搞不清楚什么时候用spin_lock,什么时候用raw_spin_lock,因此有了这篇文章。
/*****************************************************************************************************/
声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢!
/*****************************************************************************************************/
1. 临界区(Critical Section)
能小的范围内。临界区内需要对这些数据对象和硬件对象的访问进行保护,保证在退出临界区前不会被临界区外的代码对这些对象进行修改。出现以下几种情形时,
我们需要使用临界区进行保护:
- (1) 在可以抢占(preemption)的系统中,两个线程同时访问同一个对象;
- (2) 线程和中断同时访问同一个对象;
- (3) 在多核系统中(SMP),可能两个CPU可能同时访问同一个对象;
2. 自旋锁(spin_lock)
- preempt_disable();
- .....
- // 访问共享对象的代码
- ......
- preempt_enable();
同样地,针对单处理器系统,第二种情况,只要临时关闭中断即可,我们可以使用以下方法:
- local_irq_disable();
- ......
- // 访问共享对象的代码
- ......
- local_irq_enable();
那么,针对多处理器的系统,以上的方法还成立么?答案很显然:不成立。
对于第一种情况,虽然抢占被禁止了,可是另一个CPU上还有线程在运行,如果这个线程也正好要访问该共享对象,上面的代码段显然是无能为力了。
对于第二种情况,虽然本地CPU的中断被禁止了,可是另一个CPU依然可以产生中断,如果他的中断服务程序也正好要访问该共享对象,上面的代码段也一样无法对共享对象进行保护。
- spin_lock(spinlock_t *lock);
- spin_unlock(spinlock_t *lock);
对于单处理器系统,在不打开调试选项时,spinlock_t实际上是一个空结构,把上面两个函数展开后,实际上就只是调用
preempt_disable()和preempt_enable(),对于单处理器系统,关掉抢占后,其它线程不能被调度运行,所以并不需要做额外的
工作,除非中断的到来,不过内核提供了另外的变种函数来处理中断的问题。
用preempt_disable()和preempt_enable()防止线程被抢占外,还必须对spinlock_t上锁,这样,如果另一个CPU
的代码要使用该临界区对象,就必须进行自旋等待。
- spin_lock_irq(spinlock_t *lock);
- spin_unlock_irq(spinlock_t *lock);
和:
- spin_lock_irqsave(lock, flags);
- spin_lock_irqrestore(lock, flags);
我们可以按以下原则使用上面的三对变种函数(宏):
- 如果只是在普通线程之间同时访问共享对象,使用spin_lock()/spin_unlock();
- 如果是在中断和普通线程之间同时访问共享对象,并且确信退出临界区后要打开中断,使用spin_lock_irq()/spin_unlock_irq();
- 如果是在中断和普通线程之间同时访问共享对象,并且退出临界区后要保持中断的状态,使用spin_lock_irqsave()/spin_unlock_irqrestore();
其实变种还不止这几个,还有read_lock_xxx/write_lock_xxx、spin_lock_bh/spin_unlock_bh、spin_trylock_xxx等等。但常用的就上面几种。
3. raw_spin_lock
spinlock_t变为了raw_spinlock_t。而且在内核的主线版本中,spin_lock系列只是简单地调用了raw_spin_lock
系列的函数,但内核的代码却是有的地方使用spin_lock,有的地方使用raw_spin_lock。是不是很奇怪?要解答这个问题,我们要回到
2004年,MontaVista Software, Inc的开发人员在邮件列表中提出来一个Real-Time
Linux Kernel的模型,旨在提升Linux的实时性,之后Ingo
Molnar很快在他的一个项目中实现了这个模型,并最终产生了一个Real-Time preemption的patch。
作。当时内核中已经有大约10000处使用了自旋锁的代码,直接修改spin_lock将会导致这个patch过于庞大,于是,他们决定只修改哪些真正不
允许抢占和休眠的地方,而这些地方只有100多处,这些地方改为使用raw_spin_lock,但是,因为原来的内核中已经有
raw_spin_lock这一名字空间,用于代表体系相关的原子操作的实现,于是linus本人建议:
- 把原来的raw_spin_lock改为arch_spin_lock;
- 把原来的spin_lock改为raw_spin_lock;
- 实现一个新的spin_lock;
写到这里不知大家明白了没?对于2.6.33和之后的版本,我的理解是:
- 尽可能使用spin_lock;
- 绝对不允许被抢占和休眠的地方,使用raw_spin_lock,否则使用spin_lock;
- 如果你的临界区足够小,使用raw_spin_lock;
对于没有打上Linux-RT(实时Linux)的patch的系统,spin_lock只是简单地调用raw_spin_lock,实际上他们是完全一
样的,如果打上这个patch之后,spin_lock会使用信号量完成临界区的保护工作,带来的好处是同一个CPU可以有多个临界区同时工作,而原有的
体系因为禁止抢占的原因,一旦进入临界区,其他临界区就无法运行,新的体系在允许使用同一个临界区的其他进程进行休眠等待,而不是强占着CPU进行自旋操
作。写这篇文章的时候,内核的版本已经是3.3了,主线版本还没有合并Linux-RT的内容,说不定哪天就会合并进来,也为了你的代码可以兼容
Linux-RT,最好坚持上面三个原则。
自旋锁spin_lock和raw_spin_lock的更多相关文章
- 自旋锁spin_lock和raw_spin_lock【转】
转自:http://blog.csdn.net/droidphone/article/details/7395983 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 临界区Cr ...
- [内核同步]自旋锁spin_lock、spin_lock_irq 和 spin_lock_irqsave 分析
转自:http://blog.csdn.net/wh_19910525/article/details/11536279 自旋锁的初衷:在短期间内进行轻量级的锁定.一个被争用的自旋锁使得请求它的线程在 ...
- [内核同步]自旋锁spin_lock、spin_lock_irq 和 spin_lock_irqsave 分析【转】
转自:https://www.cnblogs.com/x_wukong/p/8573602.html 转自;https://www.cnblogs.com/aaronLinux/p/5890924.h ...
- 自旋锁spin_lock、spin_lock_irq 和 spin_lock_irqsave
自旋锁和互斥锁的区别是,自旋锁不会引起睡眠,所以可用于不能休眠的代码中(如IRQ) 自旋锁保持期间抢占失效,而信号量保持期间可以被抢占 定义 spinlock_t lock; init #define ...
- 漫画|Linux 并发、竞态、互斥锁、自旋锁、信号量都是什么鬼?(转)
知乎链接:https://zhuanlan.zhihu.com/p/57354304 1. 锁的由来? 学习linux的时候,肯定会遇到各种和锁相关的知识,有时候自己学好了一点,感觉半桶水的自己已经可 ...
- 自旋锁spinlock
1 在单处理器上的实现 单核系统上,不存在严格的并发,因此对资源的共享主要是多个任务分时运行造成的. 只要在某一时段,停止任务切换,并且关中断(对于用户态应用程序,不大可能与中断处理程序抢临界区资源) ...
- LINUX内核笔记:自旋锁
目录 自旋锁作用与基本使用方法? 在SMP和UP上的不同表现? 自旋锁与上下文 使用spin_lock()后为什么不能睡眠? 强调:锁什么? 参考 1.自旋锁作用与基本使用方法? 与其他锁一样,自 ...
- spinlock自旋锁de使用
Linux内核中最常见的锁是自旋锁.一个自旋锁就是一个互斥设备,它只能有两个值:"锁定"和"解锁".如果锁可用,则"锁定"位被设置,而代码继 ...
- linux内核--自旋锁的理解
http://blog.chinaunix.net/uid-20543672-id-3252604.html 自旋锁:如果内核配置为SMP系统,自旋锁就按SMP系统上的要求来实现真正的自旋等待,但是对 ...
随机推荐
- AngularJS(17)-Angular小程序
现在可以开始创建您的第一个 AngularJS 应用程序,一个 AngularJS 单页 Web 应用. <!DOCTYPE html> <html lang="en&qu ...
- [大牛翻译系列]Hadoop(16)MapReduce 性能调优:优化数据序列化
6.4.6 优化数据序列化 如何存储和传输数据对性能有很大的影响.在这部分将介绍数据序列化的最佳实践,从Hadoop中榨出最大的性能. 压缩压缩是Hadoop优化的重要部分.通过压缩可以减少作业输出数 ...
- Ubuntu 在未知root密码的情况下修改root密码
一, 开机按 F12 (或长按Shift), 进入GRUB界面. 二, 在 recovery mode 按e Ubuntu, Linux 3.5.0-17-generic (恢复模式) (或recov ...
- laravel--has方法--查看关联关系
has()方法可以用来查询是否有关联关系的一个东西,一般其他的has方法 就是判断这个里面有没有值 $packageOrders = Company::has('packages')->get( ...
- PHP获取上个月、下个月、本月的日期(strtotime(),date())
今天写程序的时候,突然发现了很早以前写的获取月份天数的函数,经典的switch版,但是获得上月天数的时候,我只是把月份-1了,估计当时太困了吧,再看到有种毛骨悚然的感觉,本来是想再处理一下的,但是一想 ...
- [转]Linux中find常见用法示例
Linux中find常见用法示例[转]·find path -option [ -print ] [ -exec -ok command ] {} \;find命令的参 ...
- C#不同页面之间通信的方法
以前做项目的时候经常头疼两个页面之间的交互(汗),这几天看的MVVM项目,忽然感觉好简单的!我自己写了个简单的demo 可以简单实现2个页面之间的交互,新人第一次发博客,不喜勿喷 代码很简单,注释我就 ...
- 《.NET简单企业应用》技术路线
前言 工作三年了,一直从事基于.NET体系的企业应用开发,心得和经验也攒了点:担心时间长了给忘了,所以得给写下来,以便以后回味回味:更重要的是能让知识系统化和体系化. 本系列以一个简单的企业应用系统为 ...
- MYSQL 配置slave故障
之前为主从配置,后来分割成2个单实例.现在环境需要,重新配置为主从,之前参数都已配置好,直接启动,如下: mysql> change master to master_host='192.168 ...
- Android--消除“Permission is only granted to system apps”错误
原文:http://blog.csdn.net/gaojinshan/article/details/14230673 在AndroidManifest.xml中使用了如下的配置: <uses- ...