并发是指多个执行单元同时、并行被执行,而并发的执行单位对于共享资源(硬件资源和软件上的全局变量、静态变量等)的访问很容易致使竞态(race conditions)linux
竞态主要发生在以下几种状况:安全
一、对称多处理器(SMP)的多个CPU并发
二、单CPU内进程与抢占它的进程函数
三、中断(硬中断、软中断、Tasklet、底半部)与进程之间测试
四、中断也可能被更高优先级的中断打断,所以,多个中断之间也可能引发并发致使竞态spa
解决竞态问题的途径是保证对共享资源的互斥访问,所谓互斥访问是指一个执行单元在访问共享资源的时候,其余的执行单元被禁止访问。递归
访问共享资源的代码区成为临界区,临界区须要被以某种互斥机制加以保护,中断屏蔽、原子操做、自旋锁和信号量是linux设备驱动中可采用的互斥途径。进程
一、中断屏蔽:只能禁止和使能本CPU内的中断。资源
二、原子操做:是指在执行过程当中不会被别的代码路径所中断的操做。内核代码能够安全的调用它们而不被打断。分为针对位和整形变量进行原子操做两类同步
三、自旋锁:理解它最简单的方法是把它看成一个变量看待,该变量把一个临界区标记为”我当前在运行,请稍等一会“或者标记为”我当前不在运行,能够被使用“
使用自旋锁能够保证临界区不受别的CPU和本CPU内的抢占进程打扰,可是获得锁的代码路径在执行临界区的时候,还可能受到中断和底半部的影响。
为防止这种影响,须要用到自旋锁的衍生。能够避免突如其来的中断对系统形成的伤害。
使用自旋锁需注意以下:
一、其实是忙等锁,当锁不可用时,CPU一直循环执行”测试并设置“该锁直到可用而取得该锁,CPU在等待自旋锁时不作任何有用的工做,仅仅是等待。
所以,只有在占有锁的时间极短的状况下,使用自旋锁才是合理的。
二、自旋锁可能致使死锁。引起这个问题最多见的状况是递归使用一个自旋锁,即若是一个已经拥有某个自旋锁的CPU想第二次得到这个锁,则CPU将死锁
三、自旋锁锁按期间不能调用可能引发进程调度的函数。若是进程获取自旋锁以后阻塞,如调用copy_from_user()\copy_to_user()\kmalloc()和msleep
等,则可能致使内核崩溃。
四、信号量:只有获得信号量的进程才能执行临界区代码,与自旋锁不一样的是,当获取不到信号量时,进程不会原地打转而是进入休眠等待状态,不能用在中断上下文中
若是信号量被初始化为0,则它能够用于同步,同步意味着一个执行单元的继续执行需等待另外一执行单元完成某事。
信号量和自旋锁的区别:
一、信号量是进程级的,用于多个进程之间对资源的互斥,。鉴于进程上下文的切换开销较大,只有当进程占用资源时间较长时,用信号量才是较好的选择,
当所要保护的临界区访问时间较短时,用自旋锁是较好的
二、信号量所保护的临界区可包含可能引发阻塞的代码,而自旋锁要避免,由于阻塞意味着要进行进程的切换,若是进程切换出去后,另外一个进程企图得到
本自旋锁,死锁将发生
三、信号量存在于进程上下文,所以,若是被保护的共享资源须要在中断或软中断状况下使用,则在信号量和自旋锁之间只能选择自旋锁。