最近在内核频繁使用了自旋锁,自旋锁如果使用不当,极易引起死锁,在此总结一下。

自旋锁是一个互斥设备,它只有两个值:“锁定”和“解锁”。它通常实现为某个整数值中的某个位。希望获得某个特定锁得代码测试相关的位。如果锁可用,则“锁定”被设置,而代码继续进入临界区;相反,如果锁被其他人获得,则代码进入忙循环(而不是休眠,这也是自旋锁和一般锁的区别)并重复检查这个锁,直到该锁可用为止,这就是自旋的过程。“测试并设置位”的操作必须是原子的,这样,即使多个线程在给定时间自旋,也只有一个线程可获得该锁。

自旋锁最初是为了在多处理器系统(SMP)使用而设计的,但是只要考虑到并发问题,单处理器在运行可抢占内核时其行为就类似于SMP。因此,自旋锁对于SMP和单处理器可抢占内核都适用。可以想象,当一个处理器处于自旋状态时,它做不了任何有用的工作,因此自旋锁对于单处理器不可抢占内核没有意义,实际上,非抢占式的单处理器系统上自旋锁被实现为空操作,不做任何事情。

自旋锁有几个重要的特性:1、被自旋锁保护的临界区代码执行时不能进入休眠。2、被自旋锁保护的临界区代码执行时是不能被被其他中断中断。3、被自旋锁保护的临界区代码执行时,内核不能被抢占。从这几个特性可以归纳出一个共性:被自旋锁保护的临界区代码执行时,它不能因为任何原因放弃处理器。

考虑上面第一种情况,想象你的内核代码请求到一个自旋锁并且在它的临界区里做它的事情,在中间某处,你的代码失去了处理器。或许它已调用了一个函数(copy_from_user,假设)使进程进入睡眠。也或许,内核抢占发威,一个更高优先级的进程将你的代码推到了一边。此时,正好某个别的线程想获取同一个锁,如果这个线程运行在和你的内核代码不同的处理器上(幸运的情况),那么它可能要自旋等待一段时间(可能很长),当你的代码从休眠中唤醒或者重新得到处理器并释放锁,它就能得到锁。而最坏的情况是,那个想获取锁得线程刚好和你的代码运行在同一个处理器上,这时它将一直持有CPU进行自旋操作,而你的代码是永远不可能有任何机会来获得CPU释放这个锁了,这就是悲催的死锁。

考虑上面第二种情况,和上面第一种情况类似。假设我们的驱动程序正在运行,并且已经获取了一个自旋锁,这个锁控制着对设备的访问。在拥有这个锁得时候,设备产生了一个中断,它导致中断处理例程被调用,而中断处理例程在访问设备之前,也要获得这个锁。当中断处理例程和我们的驱动程序代码在同一个处理器上运行时,由于中断处理例程持有CPU不断自旋,我们的代码将得不到机会释放锁,这也将导致死锁。

因此,如果我们有一个自旋锁,它可以被运行在(硬件或软件)中断上下文中的代码获得,则必须使用某个禁用中断的spin_lock形式的锁来禁用本地中断(注意,只是禁用本地CPU的中断,不能禁用别的处理器的中断),使用其他的锁定函数迟早会导致系统死锁(导致死锁的时间可能不定,但是发生上述死锁情况的概率肯定是有的,看处理器怎么调度了)。如果我们不会在硬中断处理例程中访问自旋锁,但可能在软中断(例如,以tasklet的形式运行的代码)中访问,则应该使用spin_lock_bh,以便在安全避免死锁的同时还能服务硬件中断。

补充:

锁定一个自旋锁的函数有四个:

void spin_lock(spinlock_t *lock);

最基本得自旋锁函数,它不失效本地中断。

void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);

在获得自旋锁之前禁用硬中断(只在本地处理器上),而先前的中断状态保存在flags中

void spin_lockirq(spinlock_t *lock);

在获得自旋锁之前禁用硬中断(只在本地处理器上),不保存中断状态

void spin_lock_bh(spinlock_t *lock);

在获得锁前禁用软中断,保持硬中断打开状态

linux驱动 自旋锁相关推荐

  1. Linux内核自旋锁使用笔记

    Reference: spin_lock_bh()与spin_unlock_bh() Linux内核自旋锁 Linux自旋锁 Spinlock - Wikipedia, the free encycl ...

  2. linux 内核 死锁 检查,一种linux内核自旋锁死锁检测报告系统和方法与流程

    本发明涉及内核死锁检测领域,具体的说是一种linux内核自旋锁死锁检测报告系统和方法. 背景技术: linux内核死锁是长期困扰内核开发人员的问题之一,但自内核引入lockdep调试模块之后,内核死锁 ...

  3. Linux内核自旋锁

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

  4. linux内核自旋锁解释,LINUX内核笔记:自旋锁

    目录 1.自旋锁作用与基本使用方法? 与其他锁一样,自旋锁也用于保护临界区,但是自旋锁主要是用于在SMP上保护临界区.在SMP上,自旋锁最多只能被一个可执行线程持有,如果一个线程尝试获得一个被争用的自 ...

  5. linux 信号量 自旋锁 测试 实验,「正点原子Linux连载」第四十八章Linux并发与竞争实验...

    1)实验平台:正点原子Linux开发板 2)摘自<正点原子I.MX6U嵌入式Linux驱动开发指南> 关注官方微信号公众号,获取更多资料:正点原子 第四十八章Linux并发与竞争实验 在上 ...

  6. linux内核自旋锁API

    我们大概都了解,锁这种机制其实是为了保护临界区代码的,关于使用和定义,我总结的API如下: #include <linux/spinlock.h>定义自旋锁 spinlock_t lock ...

  7. Linux 内核自旋锁

    为什么需要内核自旋锁? 现在很多CPU都是几核几核的了,如果有一个变量A,CPU-X正在访问,突然CPU-Y也过来访问他,这时候就可能出现问题,因为这个A非常重要,可能导致系统崩溃,中断异常等. 我们 ...

  8. linux内核 自旋锁示例,自旋锁(示例代码)

    一.什么是自旋锁 一直以为自旋锁也是用于多线程互斥的一种锁,原来不是! 自旋锁是专为防止多处理器并发(实现保护共享资源)而引入的一种锁机制.自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用 ...

  9. linux内核自旋锁的代码分析

    前面看操作系统导论这本书,其中锁的历史变化有点感悟,现在追一下linux内核锁的代码. 一.自旋锁 1.锁的结构体 系统自旋锁结构体如下: typedef struct spinlock {union ...

最新文章

  1. Revisiting Salient Object Detection: Simultaneous Detection, Ranking, and Subitizing of Multiple Sal
  2. 使用Edge.js,在JavaScript中调用C# .Net
  3. 在线音频“三国争霸”,谁能率先登陆资本市场?
  4. Python基础-time and datetime
  5. Android Log
  6. [HttpException (0x80004005): Failed to Execute URL.]之画蛇添足之痛
  7. react的setState——读《react小书》
  8. 谈谈免费的仓库管理软件
  9. 三、 CSS3流星雨划过动画特效
  10. android 获取N天前的日期或N天后日期
  11. Ubuntu下GNOME桌面美化
  12. 前度控制器源代码分析
  13. 【华人学者风采】韩亚洪 天津大学
  14. ​Vue 3 这个坑我踩了,你们一定要小心
  15. Chap.17 总结《CL: An Introduction》 (Vyvyan Evans)
  16. 什么是MES生产制造执行系统?实施MES生产管理系统有哪些目标?
  17. matlab中的A(:)
  18. 微软TechEd大会着重宣传其虚拟化技术
  19. springboot 集成 ELK 示例
  20. 2021会宁三中高考成绩查询,2021年白银中考录取分数线查询

热门文章

  1. java.lang.UnsupportedOperationException 异常分析
  2. HDU 3572 Task Schedule
  3. thinkphp 内置函数详解
  4. BZOJ 1827: [Usaco2010 Mar]gather 奶牛大集会 树形DP
  5. 【C/C++学习】之七、指向函数的指针
  6. 坦克大战 Java版
  7. 为Java应用程序加上退出事件处理(ShutdownHook)
  8. WIN2003设完C盘权限后终端连不上。
  9. 设计行业的新宠——云渲染
  10. CodeIgniter中运用composer安装依赖包