一、什么是自旋锁

一直以为自旋锁也是用于多线程互斥的一种锁,原来不是!

自旋锁是专为防止多处理器并发(实现保护共享资源)而引入的一种锁机制。自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,“自旋”一词就是因此而得名。自旋锁在内核中大量应用于中断处理等部分(对于单处理器来说,防止中断处理中的并发可简单采用关闭中断的方式,即在标志寄存器中关闭/打开中断标志位,不需要自旋锁)。

自旋锁的初衷就是:在短期间内进行轻量级的锁定。一个被争用的自旋锁使得请求它的线程在等待锁重新可用的期间进行自旋(特别浪费处理器时间),所以自旋锁不应该被持有时间过长。如果需要长时间锁定的话, 最好使用信号量。

自旋锁只有在内核可抢占或SMP(多处理器)的情况下才真正需要,在单CPU且不可抢占的内核下,自旋锁的所有操作都是空操作。

二、自旋锁的缺陷

自旋锁是一种比较低级的保护数据结构或代码片段的原始方式,这种锁可能存在两个问题:

(1)死锁。试图递归地获得自旋锁必然会引起死锁:例如递归程序的持有实例在第二个实例循环,以试图获得相同自旋锁时,就不会释放此自旋锁。所以,在递归程序中使用自旋锁应遵守下列策略:递归程序决不能在持有自旋锁时调用它自己,也决不能在递归调用时试图获得相同的自旋锁。此外如果一个进程已经将资源锁定,那么,即使其它申请这个资源的进程不停地疯狂“自旋”,也无法获得资源,从而进入死循环。

(2)过多占用cpu资源。如果不加限制,由于申请者一直在循环等待,因此自旋锁在锁定的时候,如果不成功,不会睡眠,会持续的尝试,单cpu的时候自旋锁会让其它process动不了。因此,一般自旋锁实现会有一个参数限定最多持续尝试次数。超出后,自旋锁放弃当前time slice,等下一次机会。

由此可见,自旋锁比较适用于锁使用者保持锁时间比较短的情况。正是由于自旋锁使用者一般保持锁时间非常短,因此选择自旋而不是睡眠是非常必要的,自旋锁的效率远高于互斥锁。信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此只能在进程上下文使用,而自旋锁适合于保持时间非常短的情况,它可以在任何上下文使用。

三、Linux环境下的自旋锁

自旋锁的实现基于共享变量。一个线程通过给共享变量设置一个值来获取锁,其他等待线程查询共享变量是否为0来确定锁现是否可用,然后在忙等待的循环中“自旋”直到锁可用为止。自旋锁的状态值为1表示解锁状态,说明有1个资源可用;0或负值表示加锁状态,0说明可用资源数为0。Linux内核为通用自旋锁提供了API函数初始化、测试和设置自旋锁。API函数功能说明如下表所示:

宏定义

功能说明

spin_lock_init(lock)

初始化自旋锁,将自旋锁设置为1,表示有一个资源可用。

spin_is_locked(lock)

如果自旋锁被置为1(未锁),返回0,否则返回1。

spin_unlock_wait(lock)

等待直到自旋锁解锁(为1),返回0;否则返回1。

spin_trylock(lock)

尝试锁上自旋锁(置0),如果原来锁的值为1,返回1,否则返回0。

spin_lock(lock)

循环等待直到自旋锁解锁(置为1),然后,将自旋锁锁上(置为0)。

spin_unlock(lock)

将自旋锁解锁(置为1)。

spin_lock_irqsave(lock, flags)

循环等待直到自旋锁解锁(置为1),然后,将自旋锁锁上(置为0)。关中断,将状态寄存器值存入flags。

spin_unlock_irqrestore(lock, flags)

将自旋锁解锁(置为1)。开中断,将状态寄存器值从flags存入状态寄存器。

spin_lock_irq(lock)

循环等待直到自旋锁解锁(置为1),然后,将自旋锁锁上(置为0)。关中断。

spin_unlock_irq(lock)

将自旋锁解锁(置为1)。开中断。

spin_unlock_bh(lock)

将自旋锁解锁(置为1)。开启底半部的执行。

spin_lock_bh(lock)

循环等待直到自旋锁解锁(置为1),然后,将自旋锁锁上(置为0)。阻止软中断的底半部的执行。

在实际编程中,何时使用spin_lock,何时使用spin_lock_irq呢?这两者有点区别。

(1)spin_lock

spin_lock 的实现关系为:spin_lock -> raw_spin_lock -> _raw_spin_lock -> __raw_spin_lock ,而__raw_spin_lock 的实现为:

static inline void __raw_spin_lock(raw_spinlock_t *lock)

{

preempt_disable();

spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);

LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);

}

(2)spin_lock_irq

spin_lock_irq 的实现关系为:spin_lock_irq -> raw_spin_lock_irq -> _raw_spin_lock_irq -> __raw_spin_lock_irq,而__raw_spin_lock_irq 的实现为:

static inline void __raw_spin_lock_irq(raw_spinlock_t *lock)

{

local_irq_disable();

preempt_disable();

spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);

LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);

}

由此可见,这两者之间只有一个差别:是否调用local_irq_disable()函数, 即是否禁止本地中断。这两者的区别可以总结为:

在任何情况下使用spin_lock_irq都是安全的。因为它既禁止本地中断,又禁止内核抢占。

spin_lock比spin_lock_irq速度快,但是它并不是任何情况下都是安全的。

linux内核 自旋锁示例,自旋锁(示例代码)相关推荐

  1. Linux内核的同步机制---自旋锁

    自旋锁的思考:http://bbs.chinaunix.net/thread-2333160-1-1.html 近期在看宋宝华的<设备驱动开发具体解释>第二版.看到自旋锁的部分,有些疑惑. ...

  2. 深入linux内核架构--第五章 锁与进程间通信

    内容简介:主要讲解了Linux各个独立进程间(或线程间)相互通信的机制(主要是System V机制),由于涉及到进程间资源共享,引入资源保护问题,也就是Linux的锁. 5.1 控制机制 首先通过一个 ...

  3. Linux内核RCU(Read Copy Update)锁简析

    在非常早曾经,大概是2009年的时候.写过一篇关于Linux RCU锁的文章<RCU锁在linux内核的演变>,如今我承认.那个时候我尽管懂了RCU锁,可是我没有能力用一种非常easy的描 ...

  4. Linux内核:网络过滤器简介与示例代码

    目录 简单的例子 实施 用户空间处理 Linux的一大优点是其网络功能.路由器,交换机等许多网络产品均基于嵌入式Linux操作系统. 网络过滤是Linux内核中很好的基础结构,它使我们能够过滤和操作网 ...

  5. Linux内核分析(一)通过汇编代码,理解程序在计算机中是如何运行的

    作者:于波 声明:原创作品转载请注明出处    来源:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 首 ...

  6. 全网最牛Linux内核Makefile系统文件详解(纯文字代码)

    第一部分.概述 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows 的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,ma ...

  7. Linux内核RCU(Read Copy Update)锁简析-前传

    如果你用Linux perf tool的top命令做热点纠察时,你会发现,前10名嫌疑犯里面肯定有好几个都是锁! 在进行并行多处理时,不可 避免地会遇到锁的问题,这是不可避免的,因为这一直以来也许是保 ...

  8. Linux内核小笔记:spin_lock锁内不能使用sleep休眠

    有一个字符驱动,内部ioctl函数不同的分支均使用spin_lock和spin_unlock,以保证对外设操作的原子性.但是,有一个功能需要对一个GPIO引脚设置上下沿,于是就使用msplee来延时. ...

  9. linux内核实现ipsec,IP XFRM配置示例:利用linux kernel自带的IPSec实现,手动配置IPSec...

    1.拓扑 192.168.18.101 <=======> 192.168.18.102 2.配置192.168.18.101 ip xfrm state add src 192.168. ...

  10. Linux内核自旋锁

    Linux内核自旋锁 自旋锁 自旋锁(spinlock)是用在多个CPU系统中的锁机制,当一个CPU正访问自旋锁保护的临界区时,临界区将被锁上,其他需要访问此临界区的CPU只能忙等待,直到前面的CPU ...

最新文章

  1. 大数据工程师手册:全面系统的掌握必备知识与工具
  2. WordPress更新时提示无法连接到FTP服务器的解决方案
  3. [BUUCTF-pwn]——picoctf_2018_are you root
  4. 不到200行代码实现一个不断旋转的椭圆动画效果
  5. leetcode刷题:合并两个有序链表
  6. Jenkins+Github(Robotframework代码)
  7. XE7 Unit scope names
  8. tornado的views(templates)
  9. 将某表某列数据复制到另一张表的某列
  10. CentOs6.5配置安装DRBD
  11. 大工19春计算机文化基础在线测试3,大工19春《计算机文化基础》在线测试3.doc...
  12. 微信小程序使用图标库
  13. CMPP3.0协议(移动)
  14. Qt5+STM32F407+步进电机 | 通过电脑控制步进电机实现:6+2通道、速度可变、运动精确步数的教程——基础知识(2/4)
  15. 网站安全检测:8款非常有用的免费 Web 安全测试工具
  16. 用太极拳讲分布式理论,再不懂你来找我!
  17. StarRocks 极客营 | 王天宜:把 Usability 当产品来开发,愿运维把 StarRocks 用得飘逸
  18. hadoop、hive搭建
  19. 小米10周年发布会后,我路转粉了!
  20. 游侠的基础技术总结——前言

热门文章

  1. BZOJ3560 DZY Loves Math V
  2. java jfreechart 柱状图,JFreeChart -- 柱状图
  3. el-table单元格中加上横向柱状图
  4. mac 下 python 批量删除 PDF 中的某些页面
  5. 新店速递丨白玉兰(商务)酒店赣榆吾悦广场店 正式上线
  6. 快速翻译PDF文档的免费方法
  7. 【毕业季】致大学江湖的青葱岁月,我与湖中大的四个夏天(情忆新月,梦系信科)
  8. NodeJs之邮件(email)发送
  9. 还在说大学排名是笑话?最新规定:世界top50大学可以直接落户上海!
  10. 符号检验和置信区间R代码