(转)自旋锁(spinlock) 解释得经典,透彻

2023-10-28

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

  由于自旋锁使用者一般保持锁时间非常短,因此选择自旋而不是睡眠是非常必要的,自旋锁的效率远高于互斥锁。
  信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此只能在进程上下文使用(_trylock的变种能够在中断上下文使用),而自旋锁适合于保持时间非常短的情况,它可以在任何上下文使用。
  如果被保护的共享资源只在进程上下文访问,使用信号量保护该共享资源非常合适,如果对共巷资源的访问时间非常短,自旋锁也可以。但是如果被保护的共享资源需要在中断上下文访问(包括底半部即中断处理句柄和顶半部即软中断),就必须使用自旋锁。
  自旋锁保持期间是抢占失效的,而信号量和读写信号量保持期间是可以被抢占的。自旋锁只有在内核可抢占或SMP的情况下才真正需要,在单CPU且不可抢占的内核下,自旋锁的所有操作都是空操作。
  跟互斥锁一样,一个执行单元要想访问被自旋锁保护的共享资源,必须先得到锁,在访问完共享资源后,必须释放锁。如果在获取自旋锁时,没有任何执行单元保持该锁,那么将立即得到锁;如果在获取自旋锁时锁已经有保持者,那么获取锁操作将自旋在那里,直到该自旋锁的保持者释放了锁。
  无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。
  自旋锁的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中第一次被定义,在先前的内核中并没有该宏。
  获得自旋锁和释放自旋锁有好几个版本,因此让读者知道在什么样的情况下使用什么版本的获得和释放锁的宏是非常必要的。
  如果被保护的共享资源只在进程上下文访问和软中断上下文访问,那么当在进程上下文访问共享资源时,可能被软中断打断,从而可能进入软中断上下文来对被保护的共享资源访问,因此对于这种情况,对共享资源的访问必须使用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上软中断或中断对共享资源的非同步访问。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

(转)自旋锁(spinlock) 解释得经典,透彻 的相关文章

随机推荐

  • 安装C++的torch

    找到自己的cuda版本 nvcc version 我的输出是这样的 nvcc NVIDIA Cuda compiler driver Copyright 2005 2020 NVIDIA Corporation Built on Mon O
  • 美国设计师Aaron的Logo设计欣赏

    2007 02 16 作者 Aaron 出处 sj63 Aaron 来自美国洛杉矶 主要从事商标 标志设计
  • 解决HuggingFace加载预训练模型时报错TypeError: expected str, bytes or os.PathLike object, not NoneType

    完整报错 TypeError expected str bytes or os PathLike object not NoneType 解决方法 检查下载的组件 步骤1 完整的下载组件 包括bin文件的模型 配置文件和其他文件 尤其是to
  • 数据库系统原理练习题(十三)

    1 在数据库设计中 用E R图来描述信息结构但不涉及信息在计算机中的表示 它是数据库设计的 阶段 A 需求分析 B 概念设计 C 逻辑设计 D 物理设计 将E R模型转换成关系模型 属于数据库的 A 需求分析 B 概念设计 C 逻辑设计 D
  • AB实验的高端玩法系列4- 实验渗透低?用户未被触达?CACE/LATE

    CACE全称Compiler Average Casual Effect或者Local Average Treatment Effect 在观测数据中的应用需要和Instrument Variable结合来看 这里我们只讨论CACE的框架给
  • Java泛型的协变和逆变

    1 什么是泛型擦除 Java的泛型本质上不是真正的泛型 而是利用了类型擦除 type erasure 2 协变 covariant 和逆变 contravariant 2 1协变 covariant
  • Linux逻辑卷管理LVM

    前言 目前我们用的物理磁盘有内存限制 当我们把磁盘占满了 如果将文件放在其他磁盘对于以后的维护很是麻烦 单靠物理磁盘是无法解决空间增长的问题的这个时候逻辑卷就起到了很重要的作用 这篇文章的学习目标是 了解逻辑卷的优势特点 学会如何创建逻辑卷
  • 二维数组与稀疏数组之间的转换

    JAVA实现二维数组与稀疏数组之间的转换 一 什么是稀疏数组 稀疏数组 Sparse array 所谓稀疏数组就是数组中大部分的内容值都未被使用 或都为零 在数组中仅有少部分的空间使用 因此造成内存空间的浪费 为了节省内存空间 并且不影响数
  • JAVA循环结构

    1 循环结构特点 1 循环操作 2 循环条件 2 循环的四个步骤 1 初始化循环条件 2 循环条件 3 循环体 4 变更循环条件 3 while循环 while 循环条件 循环体 3 do while do 循环体 while 循环条件 分
  • Java上传图片文件

    PostMapping certificate public AjaxResult upCertificate MultipartFile file HttpServletRequest request AjaxResult ajax Aj
  • 素数之 积

    RSA加密算法在网络安全世界中无处不在 它利用了极大整数因数分解的难度 数据越大 安全系数越高 给定一个32位整数 请对其进行因数分解 找出是哪两个素数的乘积 思路 先判断是否为素数 再跟着条件走即可 JScript代码 let line
  • TortoiseSVN客户端重新设置用户名和密码

    在第一次使用TortoiseSVN从服务器CheckOut的时候 会要求输入用户名和密码 这时输入框下面有个选项是保存认证信息 如果选了这个选项 那么以后就不用每次都输入一遍用户名密码了 不过 如果后来在服务器端修改了用户名密码 则再次检出
  • RabbitMQ的交换机(主题模式)学习笔记

    视频地址 之前我们学习了扇出模式和直接模式 但是他们呢只能完成广播和到指定的某一个routingkey 但是如果我们想要像类似于正则表达式那样完成匹配即可接收就不行了 那么就可以使用主题模式来完成这个需要 主题模式 与扇出和直接模式差不多
  • Win10怎么添加开机启动项?Win10添加开机自动运行软件三种方法

    Win10管理开机启动项的方法相信大家已经非常熟悉 msconfig命令各系统都通用 那么很多用户发觉Win10和Win7 XP等系统不同 没有启动文件夹 那么我们怎么添加开机启动项呢 如晨软件或程序没有开机启动设置的话 是的 在Win10
  • LIMA和QLoRA论文解读

    LIMA Less Is More for Alignment paper https arxiv org abs 2305 11206 Meta在2023年5月发布了论文 LIMA Less Is More for Alignment 基
  • 容器化部署(prometheus+grafana)监控k8s集群

    prometheus images 下所有镜像导入到私有仓库 192 168 92 160 拷贝所有镜像到 master 的 images 目录下 root master images for i in gz do docker load
  • undefined reference to `vtable for’”问题的原因及解决方法

    在使用qt开发新项目时候 添加新的类是非常频繁的操作 有时候 手快 尤其程序员非常迷恋快捷键 doge 会不小心跳过一些关键步骤 导致出现一些问题 例如 undefined reference to vtable for 错误就很常见 QT
  • 获取百度搜索的返回结果

    基于request获取百度返回结果 本文基于request进行访问有可能导致SSLError 这有可能是由于本文是访问https所导致的 但这篇博客较完整地介绍了对html使用etree json对返回结果进行解析的操作 可以借鉴 Pyth
  • [Android studio] 第17节 Adapter适配器

    目录 一 Adapter是什么 二 Adapter详解 一 Adapter是什么 在 Android 开发中 适配器 Adapter 是一个关键的组件 用于将数据源绑定到界面上的视图组件 例如 ListView RecyclerView S
  • (转)自旋锁(spinlock) 解释得经典,透彻

    自旋锁与互斥锁有点类似 只是自旋锁不会引起调用者睡眠 如果自旋锁已经被别的执行单元保持 调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁 自旋 一词就是因此而得名 由于自旋锁使用者一般保持锁时间非常短 因此选择自旋而不是睡眠是非常必