目录
 
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内核设计与实现》

LINUX内核笔记:自旋锁的更多相关文章

  1. [内核同步]自旋锁spin_lock、spin_lock_irq 和 spin_lock_irqsave 分析

    转自:http://blog.csdn.net/wh_19910525/article/details/11536279 自旋锁的初衷:在短期间内进行轻量级的锁定.一个被争用的自旋锁使得请求它的线程在 ...

  2. [内核同步]自旋锁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 ...

  3. Linux内核笔记--内存管理之用户态进程内存分配

    内核版本:linux-2.6.11 Linux在加载一个可执行程序的时候做了种种复杂的工作,内存分配是其中非常重要的一环,作为一个linux程序员必然会想要知道这个过程到底是怎么样的,内核源码会告诉你 ...

  4. 【转载】linux内核笔记之进程地址空间

    原文:linux内核笔记之进程地址空间 进程的地址空间由允许进程使用的全部线性地址组成,在32位系统中为0~3GB,每个进程看到的线性地址集合是不同的. 内核通过线性区的资源(数据结构)来表示线性地址 ...

  5. 【转载】linux内核笔记之高端内存映射

    原文:linux内核笔记之高端内存映射 在32位的系统上,内核使用第3GB~第4GB的线性地址空间,共1GB大小.内核将其中的前896MB与物理内存的0~896MB进行直接映射,即线性映射,将剩余的1 ...

  6. linux内核笔记-内核同步

    linux内核就相当于不断对请求进行响应的服务器,这些请求可能来自CPU,可能来自发出中断的外部设备.我们将内核看作两种请求的侍者. (1)老板提出请求,侍者如果空闲,为老板服务.(系统调用或异常) ...

  7. [转]透过 Linux 内核看无锁编程

    非阻塞型同步 (Non-blocking Synchronization) 简介 如何正确有效的保护共享数据是编写并行程序必须面临的一个难题,通常的手段就是同步.同步可分为阻塞型同步(Blocking ...

  8. Linux内核笔记:epoll实现原理(一)

    一.说明 针对的内核版本为4.4.10. 本文只是我自己看源码的简单笔记,如果想了解epoll的实现,强烈推荐下面的文章: The Implementation of epoll(1) The Imp ...

  9. Linux内核笔记--深入理解文件描述符

    内核版本:linux-2.6.11 文件描述符(file descriptor)在Linux编程里随处可见,设备读写.网络通信.进程通信,fd可谓是关键中的关键. 深入理解可以增加我们使用它的信心. ...

随机推荐

  1. 转载java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.spinner/com.example.spinner.MainActivity}: java.lang.NullPointerException

    今天学习Android开发突然遇到了这个问题,查阅了很多资料,并且对集中原因进行了分析. 错误信息字符串:java.lang.RuntimeException: Unable to start act ...

  2. Java--关于计算表达式中赋值的细节问题

    public class Test { public static void main(String[] args) { int t = 0; int p = 0; int q = 0; int ta ...

  3. reactjs学习一(环境搭配react+es6+webpack热部署)

    reactjs学习一(环境搭配react+es6+webpack热部署) 本文的源码在这里下载 https://github.com/tianxiangbing/webpack-study   或者使 ...

  4. ios UI 适配布局相关文章

    1. http://lvwenhan.com/ios/430.html 2 . http://blog.csdn.net/liangliang103377/article/details/400822 ...

  5. 115个Java面试题和答案——终极列表(下)

    第一篇讨论了面向对象编程和它的特点,关于Java和它的功能的常见问题,Java的集合类,垃圾收集器,本章主要讨论异常处理,Java小应用程序,Swing,JDBC,远程方法调用(RMI),Servle ...

  6. Android 短信的备份

    接着上文<Android 内容提供者的实现>,继续实战 打开File Exploer,找到mmssms.db数据库,导出 打开mmssms.db 新建项目,布局如下: <Relati ...

  7. iOS UIProgressView控件用法

    IOS中进度条控件的用法总结. 进度条控件是IOS开发中一个简单的系统控件,使用总结如下: 初始化一个进度条: - (instancetype)initWithProgressViewStyle:(U ...

  8. linker command failed with exit code 1 (use -v to see invocation)解决办法

    [cpp] view plaincopy Undefined symbols for architecture i386:     "_OBJC_CLASS_$_FMDatabase&quo ...

  9. iOS关于启动页自定义特殊处理

    平常开发中对于启动页可能会有一些特别的要求,比如在启动页加动画或加一些按键可以响应事件等,最近项目中要在启动页增加版本号,因为版本号是不断的改变,所以要动态实现把它加到启动页上:在XCode上面配置的 ...

  10. sdk的目录结构及其功能

    sdk的目录结构及其功能 add-ons: 这里面保存着附加库,比如GoogleMaps,当然你如果安装OphoneSDK,这里也会有一些类库在里面. build-tools: 各个版本的sdk编译工 ...