【发布时间】:2017-11-27 18:27:35
【问题描述】:
Linux 内核 2.6 引入了一个新的每线程字段——preempt_count——每当获取/释放锁时,该字段就会递增/递减。该字段用于允许内核抢占:“如果设置了need_resched 并且preempt_count 为零,则更重要的任务是可运行的,并且抢占是安全的。”
根据罗伯特·洛夫的"Linux Kernel Development" book: “那么什么时候重新调度是安全的?只要内核不持有锁,内核就能够抢占内核中运行的任务。”
我的问题是:为什么在内核中运行的任务持有锁时抢占它不安全?
如果另一个任务被调度并试图获取锁,它将阻塞(或自旋直到它的时间片结束),所以我们不会同时让两个线程进入同一个临界区。如果我们确实抢占了在内核模式下持有锁的任务,任何人都可以概述一个有问题的场景吗?
谢谢!
【问题讨论】:
-
起初我认为另一个stackoverflow问题([stackoverflow.com/questions/5215958/…)提供了一个可能的解决方案:在持有锁的同时切换任务可能会导致死锁,例如,如果两个任务以不同的顺序获取锁。但我不认为这是答案,因为内核无论如何都应该强制执行相同的锁定顺序,以防止多处理器系统上的死锁。并且 Robert Love 还说:“因为内核是 SMP 安全的,如果没有持有锁,当前代码是可重入的并且能够被抢占。”
-
但是对所提到的问题的确切答案就是对您问题的回答。你说的是锁定顺序,但是问题中single lock时没有顺序。再说一遍:在持有锁的同时禁用抢占是内核防止死锁的方法,即使在单锁上也是如此。
-
@Tsyvarev:但是如何我们才能陷入僵局?让我们假设线程#1 持有一个锁并放弃了 CPU。然后安排线程#2,尝试获取锁,然后阻塞。最终,线程#2 完成了它的时间片,所以线程#1 再次被调度,释放锁,一切都很好。我错过了什么吗?
-
Eventually, thread #2 finishes its time slice- 1. 线程#2 的整个时间片将是浪费时间。锁成本太高了。 2. 线程的调度属性(如优先级)可能会延迟切换回线程#1 甚至更多。无限延迟意味着死锁。 -
@Tsyvarev:Robert Love 正在谈论“安全”,IMO 更多的是关于正确性而不是性能,所以我不确定“浪费时间”是否是答案。
标签: multithreading linux-kernel preemption