一、什么是死锁
死锁就是多个任务互相等着对方先放手,结果谁也动不了,卡住啦。这种情况程序自己没法解决,只能重启或者找人帮忙强制结束才能继续运行。
二、spin_lock 发生死锁情况 1
spin_lock 的作用是让系统在需要时快速安全地访问共享资源。它的工作方式是:当某个 CPU 正在使用资源时,会暂时禁止其他任务打断当前进程。但这里有个问题:如果此时突然有硬件中断(比如网络数据到达),触发了中断处理程序,而这个处理程序也需要访问同一资源,就会出问题。
死锁场景
此时当前进程已经占用了资源锁,中断处理程序只能等待锁被释放。但因为进程被 Spin Lock 禁止切换,必须等它主动让出 CPU 才能继续执行——而进程又在等待中断处理完成(比如等待数据处理完毕),这就形成了僵局:进程卡在等待中断,中断卡在等待锁,双方互相等待无法继续。这种互相等待的情况就叫做死锁。

当多个任务需要同时访问同一段关键代码时,我们会用自旋锁来保护这段区域。如果此时既有程序在运行,又有硬件中断请求,就需要先关闭 CPU 的中断功能。这样在锁定资源后,就不会被突然到来的中断打断,确保这段代码不会被其他任务抢占。
这就是为什么需要使用 spin_lock_irq 这个函数——它同时完成了"关闭中断"和"加锁"两个操作。不过这样做有两个缺点:一是系统处理其他请求的速度会变慢,因为中断被暂时关闭了;二是多了一步操作流程,可能会让程序运行得稍微慢一点。
三、发生死锁情况 2:spin_lock_irq
当一个进程先执行 spin_lock_irq(&lock1) 时,会直接关掉中断并占用锁 1。接着如果再用 spin_lock_irq(&lock2) 占用锁 2,此时中断仍然处于关闭状态。等释放锁 2 时,执行 spin_unlock_irq() 会强行打开中断,但此时还没释放锁 1,代码还在锁 1 的保护区域里运行。
死锁场景
这时问题就来了:如果刚打开中断就有硬件中断触发,中断处理程序可能又要占用锁 1。但当前进程还拿着锁 1 不放,中断程序只能傻等,最后两边都卡住——这就形成了死锁。因为释放锁 2 时强行开中断,让中断有机会运行,却没保证锁的安全性。
而 spin_lock_irqsave 就不会这样。它在占用锁时会记住中断原本是开还是关的(比如用一个变量保存状态),等释放锁时只恢复最初的中断状态,而不是强行开中断。这样既避免了中途意外打开中断导致的死锁,又能确保锁的正确使用。不过这种方法需要多存一次状态,速度会比简单版稍微慢一点。
简单总结
直接用 spin_lock_irq 可能因中途开中断引发死锁,而 spin_lock_irqsave 通过记录状态更安全,但会慢一点点。

四、总结
spin_lock不推荐使用。它可能导致程序卡死(死锁),所以一般不用。仅在需要极高的实时性时才考虑用它(比如必须立刻完成操作,不能等待)。spin_lock_irq和spin_lock类似,但会关闭所有中断(连硬件中断也会被暂停)。同样可能死锁,所以也不安全。仅在绝对需要极高实时性时使用(比如实时性比中断响应更重要)。spin_lock_irqsave最安全的选择!它会记录中断状态,用完后自动恢复中断。虽然实时性稍差(因为需要保存状态),但能避免死锁问题,是推荐优先使用的方案。
经验总结
如果不确定资源是否会被中断或抢占,直接用 spin_lock_irqsave。它虽然稍微慢一点,但能避免很多问题。