我正在阅读Robert Love的Linux Kernel Development,并试图了解内核同步机制。我试图理解与书中提到的锁定机制有关的一些要点-
”某些情况不需要自旋锁,但确实需要禁用内核抢占。这些情况中最常见的是每个处理器的数据。如果数据对于每个处理器都是唯一的,则可能不需要使用一个锁,因为只有一个处理器可以访问数据。如果没有旋转锁,则内核是抢占式的,新调度的任务可能会访问该变量。
因此,即使这是一台单处理器计算机,也可以通过多个进程伪并行访问该变量。通常,此变量需要自旋锁(以防止在多处理机上真正并发)。但是,如果这是每个处理器的变量,则可能不需要锁定。要解决此问题,可以通过preempt_disable()“
禁用内核抢占。所以在这里考虑一个多处理器系统- 我了解到,虽然当前进程正在操纵每个cpu变量,但由于SMP可能会安排另一个进程,并尝试操纵相同的每个cpu变量,因此,如书中所述,需要禁用抢占。但是我无法理解的一点是,如果我们仅禁用内核抢占,并且当前进程正在尝试操纵每个CPU数据,并且同时在当前处理器上发生了中断,并且由于该中断尚未被处理,该怎么办?禁用后,CPU停止当前任务并开始执行中断处理程序。现在,该处理程序还希望操作相同的per-cpu变量。那么在这种情况下,变量可能最终包含不一致的数据?
那么这是否意味着如果还可以从中断处理程序访问per-cpu变量,则还需要在当前处理器上禁用该中断?
平台:x86上的Linux
答案 0 :(得分:1)
所以在这里考虑一个多处理器系统-我知道 per-cpu变量正在由当前进程操纵,另一个 SMP可能会安排进程,并尝试对其进行操作 每个cpu变量,因此需要禁用抢占功能,因为 在书中解释。
我认为SMP在这里没有发挥任何作用,因为变量是按CPU分配的(在处理器之间不共享)。由于调度程序中断将会到来,而与SMP无关,并且可能在单处理器系统上发生,因此可能会推迟另一个进程。为了避免这种抢占,请使用禁用功能。对于具有 CONFIG_PREEMPT_ENABLE linux kernel says spinlock/unlock = preemp disable/enable
的单处理器系统这是否意味着该中断也需要在 当前处理器,如果还可以从以下位置访问per-cpu变量 中断处理程序?
是的!对于单处理器系统也是如此。在这种情况下,您应该使用irqsave API(或等效方法):
spin_lock_irqsave(&xxx_lock, flags);
... critical section here ..
spin_unlock_irqrestore(&xxx_lock, flags);
对于单处理器内核,此自旋锁将变为本地irq启用/禁用。在SMP系统中,自旋锁是通过cmpxchg + irq禁用/启用实现的实际自旋锁。
答案 1 :(得分:0)
对于多处理器系统和保护 percpu 变量,我们可以禁用抢占并执行 local_irq_save。这样我们就可以避免使用自旋锁。自旋锁需要跨多个 CPU 的原子性。对于每个 cpu 变量,不需要它。
local_irq_save(flags);
preempt_disable();
-- Modify the percpu variable
preempt_enable();
local_irq_restore(flags);
使用此代码,其他 CPU 可以并行工作。没有一个 CPU 旋转。
如果我们使用自旋锁,那么我们修改一个原子变量,其他 CPU 也来了,如果获取自旋锁,它必须等待/自旋。