快速业务通道

spinlock与linux内核调度的关系

作者 佚名技术 来源 Linux系统 浏览 发布时间 2012-04-14

作者:刘洪涛,华清远见嵌入式学院高级讲师,ARM公司授权ATC讲师.

关于自旋锁用法介绍的文章,已经有很多,但有些细节的地方点的还不够透.我这里就把我个人认为大家容易有疑问的地方拿出来讨论一下.

一、自旋锁(spinlock)简介

自旋锁在同一时刻只能被最多一个内核任务持有,一个时刻只有一个线程允许存在于临界区中.这点可以应用在多处理机器、或运行在单处理器上的抢占式内核中需要的锁定服务.

二、信号量简介

这里也介绍下信号量的概念,它的用法和自旋锁有相似的地方.

Linux中的信号量是一种睡眠锁.如果有一个任务试图获得一个已被持有的信号量时,信号量会将其推入等待队列,然后让其睡眠.这时处理器获得自由去执行其它代码.当持有信号量的进程将信号量释放后,在等待队列中的一个任务将被唤醒,从而便可以获得这个信号量.

三、自旋锁和信号量对比

在很多地方自旋锁和信号量可以选择任何一个使用,但也有一些地方只能选择某一种.下面对比一些两者的用法.

表1-1自旋锁和信号量对比

应用场合

信号量or自旋锁

低开销加锁(临界区执行时间较快)

优先选择自旋锁

低开销加锁(临界区执行时间较长)

优先选择信号量

临界区可能包含引起睡眠的代码

不能选自旋锁,可以选择信号量

临界区位于非进程上下文时,此时不能睡眠

优先选择自旋锁,即使选择信号量也只能用down_trylock非阻塞的方式

四、自旋锁与linux内核进程调度关系

我们讨论下表1-1中的第3种情况(其它几种情况比较好理解),如果临界区可能包含引起睡眠的代码则不能使用自旋锁,否则可能引起死锁.

那么为什么信号量保护的代码可以睡眠而自旋锁就不能呢?

先看下自旋锁的实现方法吧,自旋锁的基本形式如下:

spin_lock(&mr_lock);

//临界区

spin_unlock(&mr_lock);

跟踪一下spin_lock(&mr_lock)的实现

#define spin_lock(lock) _spin_lock(lock)

#define _spin_lock(lock) __LOCK(lock)

#define __LOCK(lock)

do { preempt_disable(); __acquire(lock); (void)(lock); } while (0)

注意到“preempt_disable()”,这个调用的功能是“关抢占”(在spin_unlock中会重新开启抢占功能).从中可以看出,使用自旋锁保护的区域是工作在非抢占的状态;即使获取不到锁,在“自旋”状态也是禁止抢占的.了解到这,我想咱们应该能够理解为何自旋锁保护的代码不能睡眠了.试想一下,如果在自旋锁保护的代码中间睡眠,此时发生进程调度,则可能另外一个进程会再次调用spinlock保护的这段代码.而我们现在知道了即使在获取不到锁的“自旋”状态,也是禁止抢占的,而“自旋”又是动态的,不会再睡眠了,也就是说在这个处理器上不会再有进程调度发生了,那么死锁自然就发生了.

咱们可以总结下自旋锁的特点:

● 单处理器非抢占内核下:自旋锁会在编译时被忽略;

● 单处理器抢占内核下:自旋锁仅仅当作一个设置内核抢占的开关;

● 多处理器下:此时才能完全发挥出自旋锁的作用,自旋锁在内核中主要用来防止多处理器中并发访问临界区,防止内核抢占造成的

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号