1 基础概念

自旋锁与相互排斥锁有点类似,仅仅是自旋锁不会引起调用者睡眠。假设自旋锁已经被别的运行单元保持。调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁。"自旋"一词就是因此而得名。

  因为自旋锁使用者一般保持锁时间很短,因此选择自旋而不是睡眠是很必要的,自旋锁的效率远高于相互排斥锁。

  信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此仅仅能在进程上下文使用(_trylock的变种可以在中断上下文使用)。而自旋锁适合于保持时间很短的情况,它可以在不论什么上下文使用。

  假设被保护的共享资源仅仅在进程上下文訪问,使用信号量保护该共享资源很合适,假设对共巷资源的訪问时间很短,自旋锁也能够。可是假设被保护的共享资源须要在中断上下文訪问(包含底半部即中断处理句柄和顶半部即软中断)。就必须使用自旋锁。

  自旋锁保持期间是抢占失效的,而信号量和读写信号量保持期间是能够被抢占的。

自旋锁仅仅有在内核可抢占或SMP的情况下才真正须要。在单CPU且不可抢占的内核下,自旋锁的全部操作都是空操作。

  跟相互排斥锁一样,一个运行单元要想訪问被自旋锁保护的共享资源,必须先得到锁,在訪问完共享资源后。必须释放锁。假设在获取自旋锁时,没有不论什么运行单元保持该锁,那么将马上得到锁;假设在获取自旋锁时锁已经有保持者,那么获取锁操作将自旋在那里,直到该自旋锁的保持者释放了锁。

2 自旋锁的API



spin_lock_init(x)

  该宏用于初始化自旋锁x。自旋锁在真正使用前必须先初始化。

该宏用于动态初始化。

DEFINE_SPINLOCK(x)

  该宏声明一个自旋锁x并初始化它。

该宏在2.6.11中第一次被定义。在先前的内核中并没有该宏。

SPIN_LOCK_UNLOCKED

  该宏用于静态初始化一个自旋锁。

DEFINE_SPINLOCK(x)等同于spinlock_t x = SPIN_LOCK_UNLOCKED spin_is_locked(x)

  该宏用于推断自旋锁x是否已经被某运行单元保持(即被锁),假设是。返回真,否则返回假。

spin_unlock_wait(x)

  该宏用于等待自旋锁x变得没有被不论什么运行单元保持,假设没有不论什么运行单元保持该自旋锁,该宏马上返回。否则将循环在那里。直到该自旋锁被保持者释放。

spin_trylock(lock)

  该宏尽力获得自旋锁lock,假设能马上获得锁,它获得锁并返回真。否则不能马上获得锁。马上返回假。它不会自旋等待lock被释放。

spin_lock(lock)

  该宏用于获得自旋锁lock,假设可以立即获得锁。它就立即返回,否则。它将自旋在那里,直到该自旋锁的保持者释放。这时。它获得锁并返回。

总之。仅仅有它获得锁才返回。

spin_lock_irqsave(lock, flags)

  该宏获得自旋锁的同一时候把标志寄存器的值保存到变量flags中并失效本地中断。

spin_lock_irq(lock)

  该宏类似于spin_lock_irqsave。仅仅是该宏不保存标志寄存器的值。

spin_lock_bh(lock)

  该宏在得到自旋锁的同一时候失效本地软中断。

spin_unlock(lock)

  该宏释放自旋锁lock,它与spin_trylock或spin_lock配对使用。假设spin_trylock返回假,表明没有获得自旋锁。因此不必使用spin_unlock释放。

spin_unlock_irqrestore(lock, flags)

  该宏释放自旋锁lock的同一时候,也恢复标志寄存器的值为变量flags保存的值。它与spin_lock_irqsave配对使用。

spin_unlock_irq(lock)

  该宏释放自旋锁lock的同一时候。也使能本地中断。它与spin_lock_irq配相应用。

spin_unlock_bh(lock)

  该宏释放自旋锁lock的同一时候,也使能本地的软中断。

它与spin_lock_bh配对使用。

spin_trylock_irqsave(lock, flags)

  该宏假设获得自旋锁lock,它也将保存标志寄存器的值到变量flags中,而且失效本地中断,假设没有获得锁,它什么也不做。

  因此假设可以马上获得锁。它等同于spin_lock_irqsave。假设不能获得锁。它等同于spin_trylock。假设该宏获得自旋锁lock。那须要使用spin_unlock_irqrestore来释放。

spin_trylock_irq(lock)

  该宏类似于spin_trylock_irqsave。仅仅是该宏不保存标志寄存器。

假设该宏获得自旋锁lock。须要使用spin_unlock_irq来释放。

spin_trylock_bh(lock)

  该宏假设获得了自旋锁。它也将失效本地软中断。假设得不到锁,它什么也不做。因此。假设得到了锁。它等同于spin_lock_bh,假设得不到锁。它等同于spin_trylock。假设该宏得到了自旋锁。须要使用spin_unlock_bh来释放。

spin_can_lock(lock)

  该宏用于推断自旋锁lock是否可以被锁,它实际是spin_is_locked取反。假设lock没有被锁。它返回真,否则,返回假。该宏在2.6.11中第一次被定义,在先前的内核中并没有该宏。

3 API 使用场景

假设被保护的共享资源仅仅在进程上下文訪问和软中断上下文訪问,那么当在进程上下文訪问共享资源时。可能被软中断打断,从而可能进入软中断上下文来对被保护的共享资源訪问,因此对于这样的情况。对共享资源的訪问必须使用spin_lock_bh和spin_unlock_bh来保护。

  当然使用spin_lock_irq和spin_unlock_irq以及spin_lock_irqsave和spin_unlock_irqrestore也能够。它们失效了本地硬中断,失效硬中断隐式地也失效了软中断。

可是使用spin_lock_bh和spin_unlock_bh是最恰当的,它比其它两个快。

  假设被保护的共享资源仅仅在进程上下文和tasklet或timer上下文訪问,那么应该使用与上面情况同样的获得和释放锁的宏,由于tasklet和timer是用软中断实现的。

  假设被保护的共享资源仅仅在一个tasklet或timer上下文訪问。那么不须要不论什么自旋锁保护,由于同一个tasklet或timer仅仅能在一个CPU上执行。即使是在SMP环境下也是如此。

实际上tasklet在调用tasklet_schedule标记其须要被调度时已经把该tasklet绑定到当前CPU。因此同一个tasklet决不可能同一时候在其它CPU上执行。

  timer也是在其被使用add_timer加入到timer队列中时已经被帮定到当前CPU。所以同一个timer绝不可能执行在其它CPU上。当然同一个tasklet有两个实例同一时候执行在同一个CPU就更不可能了。

  假设被保护的共享资源仅仅在两个或多个tasklet或timer上下文訪问。那么对共享资源的訪问仅须要用spin_lock和spin_unlock来保护,不必使用_bh版本号,由于当tasklet或timer执行时,不可能有其它tasklet或timer在当前CPU上执行。

 假设被保护的共享资源仅仅在一个软中断(tasklet和timer除外)上下文訪问,那么这个共享资源须要用spin_lock和spin_unlock来保护,由于相同的软中断能够同一时候在不同的CPU上执行。

  假设被保护的共享资源在两个或多个软中断上下文訪问,那么这个共享资源当然更须要用spin_lock和spin_unlock来保护。不同的软中断可以同一时候在不同的CPU上执行。

  假设被保护的共享资源在软中断(包含tasklet和timer)或进程上下文和硬中断上下文訪问。那么在软中断或进程上下文訪问期间,可能被硬中断打断,从而进入硬中断上下文对共享资源进行訪问,因此。在进程或软中断上下文须要使用spin_lock_irq和spin_unlock_irq来保护对共享资源的訪问。

  而在中断处理句柄中使用什么版本号。需依情况而定,假设仅仅有一个中断处理句柄訪问该共享资源,那么在中断处理句柄中仅须要spin_lock和spin_unlock来保护对共享资源的訪问就能够了。

  由于在运行中断处理句柄期间,不可能被同一CPU上的软中断或进程打断。可是假设有不同的中断处理句柄訪问该共享资源,那么须要在中断处理句柄中使用spin_lock_irq和spin_unlock_irq来保护对共享资源的訪问。

  在使用spin_lock_irq和spin_unlock_irq的情况下。全然能够用spin_lock_irqsave和spin_unlock_irqrestore代替。那详细应该使用哪一个也须要依情况而定,假设能够确信在对共享资源訪问前中断是使能的,那么使用spin_lock_irq更好一些。

  由于它比spin_lock_irqsave要快一些,可是假设你不能确定是否中断使能。那么使用spin_lock_irqsave和spin_unlock_irqrestore更好,由于它将恢复訪问共享资源前的中断标志而不是直接使能中断。

  当然,有些情况下须要在訪问共享资源时必须中断失效,而訪问完后必须中断使能。这种情形使用spin_lock_irq和spin_unlock_irq最好。

  spin_lock用于阻止在不同CPU上的运行单元对共享资源的同一时候訪问以及不同进程上下文互相抢占导致的对共享资源的非同步訪问,而中断失效和软中断失效却是为了阻止在同一CPU上软中断或中断对共享资源的非同步訪问。

自旋锁spinlock解析的更多相关文章

  1. 自旋锁spinlock

    1 在单处理器上的实现 单核系统上,不存在严格的并发,因此对资源的共享主要是多个任务分时运行造成的. 只要在某一时段,停止任务切换,并且关中断(对于用户态应用程序,不大可能与中断处理程序抢临界区资源) ...

  2. 自旋锁-SpinLock(.NET 4.0+)

    短时间锁定的情况下,自旋锁(spinlock)更快.(因为自旋锁本质上不会让线程休眠,而是一直循环尝试对资源访问,直到可用.所以自旋锁线程被阻塞时,不进行线程上下文切换,而是空转等待.对于多核CPU而 ...

  3. SpinLock 自旋锁, CAS操作(Compare & Set) ABA Problem

    SpinLock 自旋锁 spinlock 用于CPU同步, 它的实现是基于CPU锁定数据总线的指令. 当某个CPU锁住数据总线后, 它读一个内存单元(spinlock_t)来判断这个spinlock ...

  4. SpinLock(自旋锁)

    SpinLock(自旋锁) SpinLock 结构是一个低级别的互斥同步基元,它在等待获取锁时进行旋转. 在多核计算机上,当等待时间预计较短且极少出现争用情况时,SpinLock 的性能将高于其他类型 ...

  5. LiteOS:SpinLock自旋锁及LockDep死锁检测

    摘要:除了多核的自旋锁机制,本文会介绍下LiteOS 5.0引入的LockDep死锁检测特性. 2020年12月发布的LiteOS 5.0推出了全新的内核,支持SMP多核调度功能.想学习SMP多核调度 ...

  6. linux内核--自旋锁的理解

    http://blog.chinaunix.net/uid-20543672-id-3252604.html 自旋锁:如果内核配置为SMP系统,自旋锁就按SMP系统上的要求来实现真正的自旋等待,但是对 ...

  7. 深入分析Linux自旋锁【转】

    转自:http://blog.chinaunix.net/uid-20543672-id-3252604.html 前言: 在复习休眠的过程中,我想验证自旋锁中不可休眠,所以编写了一个在自旋锁中休眠的 ...

  8. Linux内核同步:自旋锁

    linux内核--自旋锁的理解 自旋锁:如果内核配置为SMP系统,自旋锁就按SMP系统上的要求来实现真正的自旋等待,但是对于UP系统,自旋锁仅做抢占和中断操作,没有实现真正的“自旋”.如果配置了CON ...

  9. 【APUE】信号量、互斥体和自旋锁

    http://www.cnblogs.com/biyeymyhjob/archive/2012/07/21/2602015.html http://blog.chinaunix.net/uid-205 ...

随机推荐

  1. [Java开发之路](9)对象序列化与反序列化

    1. 对象序列化 当你创建对象时.仅仅要你须要.它会一直存在,可是程序终止时,不管何时它都不会继续存在.虽然这样做是很有意义的,可是在某些情况下.假设程序不执行时扔能存在而且保存其信息,那将对我们很实 ...

  2. MySql 存储引擎的选取

    存储引擎是为不同的表类型处理 SQL 操作的 MySql 组件.InnoDB 是默认的.最通用的存储引擎,也是官方推荐使用的存储引擎,除非一些特定案例.MySql 5.6 中的 CREATE TABL ...

  3. Can not find a java.io.InputStream with the name [downloadFile] in the invocation stack.

    1.错误描写叙述 八月 14, 2015 4:22:45 下午 com.opensymphony.xwork2.util.logging.jdk.JdkLogger error 严重: Excepti ...

  4. call 方法和 apply方法

    1.方法定义 call方法: 语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象. 说明: call ...

  5. | 插件下载陈磊SQL MD5 加密

    简介:SQL MD5 加密 下述是 SQL Server 中 MD5加密 16位和32位的 ,)) ,ModifiedOn=null ; ,)) ,ModifiedOn=null ;

  6. POJ 3050 枚举+dfs+set判重

    思路: 枚举+搜一下+判个重 ==AC //By SiriusRen #include <set> #include <cstdio> using namespace std; ...

  7. 量化派基于Hadoop、Spark、Storm的大数据风控架构--转

    原文地址:http://www.csdn.net/article/2015-10-06/2825849 量化派是一家金融大数据公司,为金融机构提供数据服务和技术支持,也通过旗下产品“信用钱包”帮助个人 ...

  8. linux的dhcp4.1.1服务部署

     Centos6.5的dhcp4.1.1服务部署 实施步骤: 1:设置DHCP服务器静态IP和主机名 [root@sw ~]# vim /etc/sysconfig/network-scripts/i ...

  9. kill&&pkill&&killall---删除执行中的程序

    命令功能: 发送指定的信号到相应进程.不指定型号将发送SIGTERM(15)终止指定进程.如果无法终止该程序可用“-KILL” 参数,其发送的信号为SIGKILL(9) ,将强制结束进程 使用ps命令 ...

  10. 洛谷——P2093 零件分组

    https://www.luogu.org/problem/show?pid=2093 题目描述 某工厂生产一批棍状零件,每个零件都有一定的长度(Li)和重量(Wi).现在为了加工需要,要将它们分成若 ...