【深入理解Linux内核】自旋锁

一. 信号量

信号量结构:

  • 一个整数变量
  • 一个等待进程的链表
  • 两个原子方法:down() 和 up()

每个要保护的数据结构都有它自己的信号量,初始值为1.

当内核控制路径希望访问这个数据结构是,在这个信号量上执行down(),对信号量的值-1。若当前信号量的值非负,则允许访问这个数据结构。否则,把执行内核控制路径的进程添加到这个信号量的链表中并阻塞该进程。

当另一个进程在那个信号量上执行up()时,允许信号量链表上的一个进程继续执行。

 

二. 自旋锁

1. 为什么引入?

在多处理器系统中,系统不允许在不同CPU上运行的内核控制路径同时访问某些内核数据结构。若果修改数据结构所需的时间比较短,内核必须把进程插入到信号量链表,然后挂起它,这些操作很耗时,完成这些操作时,其他的内核控制路径可能已经释放了这个信号量。

2. 自旋锁

自旋锁与信号量十分相近,但是没有进程链表:当一个进程A发现锁被另一个进程B锁着,A就不停的“旋转”,执行一个紧凑的循环指令直到锁打开。

3. 自旋锁的特点

  • 被自旋锁保护的临界区代码执行时不能进入休眠。
  • 被自旋锁保护的临界区代码执行时是不能被被其他中断中断。
  • 被自旋锁保护的临界区代码执行时,内核不能被抢占。

注:现代处理器在处理自旋锁时都会设定自旋上限时间以防死锁. 

4. 自旋锁在单处理器中、多处理器中的应用

自选锁在单处理器环境下是无效的。当内核控制路径试图访问一个上锁的数据结构时,他开始无休止的循环。在单处理器中,内核控制路径可能因为修改应该受保护的数据结构而没有机会继续执行,也没有机会释放这个自旋锁。最后的结果可能是系统挂起。因此单处理器环境不需要自旋锁。

linux上的自旋锁有三种实现:

1. 在单cpu,不可抢占内核中,自旋锁为空操作。

2. 在单cpu,可抢占内核中,自旋锁实现为“禁止内核抢占”,并不实现“自旋”。

3. 在多cpu,可抢占内核中,自旋锁实现为“禁止内核抢占” + “自旋”。

参考:https://blog.csdn.net/zqixiao_09/article/details/79265789

猜你喜欢

转载自blog.csdn.net/lxin_liu/article/details/84844303