为什么使用spinlock的时候不能睡眠

跟踪一下spin_lock(&mr_lock)的实现

#define spin_lock(lock) _spin_lock(lock)

#define _spin_lock(lock) __LOCK(lock)

#define __LOCK(lock) /

do { preempt_disable(); __acquire(lock); (void)(lock); } while (0)

注意到“preempt_disable()”,这个调用的功能是“关抢占”(在spin_unlock中会重新开启抢占功能)。从中可以看出,使 用自旋锁保护的区域是工作在非抢占的状态;即使获取不到锁,在“自旋”状态也是禁止抢占的。了解到这,我想咱们应该能够理解为何自旋锁保护的代码不能睡眠 了。试想一下,如果在自旋锁保护的代码中间睡眠,此时发生进程调度,则可能另外一个进程会再次调用spinlock保护的这段代码。而我们现在知道了即使 在获取不到锁的“自旋”状态,也是禁止抢占的,而“自旋”又是动态的,不会再睡眠了,也就是说在这个处理器上不会再有进程调度发生了,那么死锁自然就发生 了。

导致死锁的过程:

[pid] Action    ...... Comment

[1]   关抢占

[1]   获得锁

[1]   睡眠调度            ...... 尽管已经关闭了抢占,[1]依然可以通过主动调用schedule(), schedule_timeout()等主动让出CPU,调度其它进程。

[2]   关抢占               ...... [1]已经关闭抢占,所以这里相当于nop操作

[2]   获得锁失败         ...... [1]已经获得了锁,并且还没有释放

[2]   反复尝试获得锁   ...... 由于关闭了抢占,已经没人能够终止这个反复尝试的操作了,所以这里出现了死锁

跟踪一下spin_lock(&mr_lock)的实现

#define spin_lock(lock) _spin_lock(lock)

#define _spin_lock(lock) __LOCK(lock)

#define __LOCK(lock) /

do { preempt_disable(); __acquire(lock); (void)(lock); } while (0)

注意到“preempt_disable()”,这个调用的功能是“关抢占”(在spin_unlock中会重新开启抢占功能)。从中可以看出,使 用自旋锁保护的区域是工作在非抢占的状态;即使获取不到锁,在“自旋”状态也是禁止抢占的。了解到这,我想咱们应该能够理解为何自旋锁保护的代码不能睡眠 了。试想一下,如果在自旋锁保护的代码中间睡眠,此时发生进程调度,则可能另外一个进程会再次调用spinlock保护的这段代码。而我们现在知道了即使 在获取不到锁的“自旋”状态,也是禁止抢占的,而“自旋”又是动态的,不会再睡眠了,也就是说在这个处理器上不会再有进程调度发生了,那么死锁自然就发生 了。

导致死锁的过程:

[pid] Action    ...... Comment

[1]   关抢占

[1]   获得锁

[1]   睡眠调度            ...... 尽管已经关闭了抢占,[1]依然可以通过主动调用schedule(), schedule_timeout()等主动让出CPU,调度其它进程。

[2]   关抢占               ...... [1]已经关闭抢占,所以这里相当于nop操作

[2]   获得锁失败         ...... [1]已经获得了锁,并且还没有释放

[2]   反复尝试获得锁   ...... 由于关闭了抢占,已经没人能够终止这个反复尝试的操作了,所以这里出现了死锁

猜你喜欢

转载自blog.csdn.net/Qinus/article/details/84404288
今日推荐