Linux内核spin_lock、spin_lock_irq 和 spin_lock_irqsave 分析

摘自:https://blog.csdn.net/wh_19910525/article/details/11536279
在Linux内核中何时使用spin_lock,何时使用spin_lock_irqsave很容易混淆。首先看一下代码是如何实现的。

spin_lock的调用关系

     spin_lock

            |

           + ----->  raw_spin_lock


[cpp] view plaincopy
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);  
}  
spin_lock_irq的调用关系

    spin_lock_irq

                |

               +-------> raw_spin_lock_irq


[cpp] view plaincopy
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速度快,但是它并不是任何情况下都是安全的。

举个例子:进程A中调用了spin_lock(&lock)然后进入临界区,此时来了一个中断(interrupt),

该中断也运行在和进程A相同的CPU上,并且在该中断处理程序中恰巧也会spin_lock(&lock)

试图获取同一个锁。由于是在同一个CPU上被中断,进程A会被设置为TASK_INTERRUPT状态,

中断处理程序无法获得锁,会不停的忙等,由于进程A被设置为中断状态,schedule()进程调度就

无法再调度进程A运行,这样就导致了死锁!

但是如果该中断处理程序运行在不同的CPU上就不会触发死锁。 因为在不同的CPU上出现中断不会导致

进程A的状态被设为TASK_INTERRUPT,只是换出。当中断处理程序忙等被换出后,进程A还是有机会

获得CPU,执行并退出临界区。

所以在使用spin_lock时要明确知道该锁不会在中断处理程序中使用。

====================

使用spin_lock_irqsave在于你不期望在离开临界区后,改变中断的开启,关闭状态!进入临界区是关闭的,离开后它同样应该是关闭的!


如果自旋锁在中断处理函数中被用到,那么在获取该锁之前需要关闭本地中断,spin_lock_irqsave 只是下列动作的一个便利接口:
1 保存本地中断状态
2 关闭本地中断
3 获取自旋锁

解锁时通过 spin_unlock_irqrestore完成释放锁、恢复本地中断到之前的状态等工作

--------------------

还有一对 spin_lock_irq 和 spin_unlock_irq
如果你确定在获取锁之前本地中断是开启的,那么就不需要保存中断状态,解锁的时候直接将本地中断启用就可以啦
————————————————
版权声明:本文为CSDN博主「wh_19910525」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wh_19910525/java/article/details/11536279

posted @   LiuYanYGZ  阅读(830)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
历史上的今天:
2016-04-20 Linux下tar.xz结尾的文件的解压方法
2016-04-20 ubuntu Linux离线安装软件包
点击右上角即可分享
微信分享提示