锁定每个CPU变量

时间:2019-11-01 19:00:16

标签: linux linux-kernel synchronization locking

我正在阅读Robert Love的Linux Kernel Development,并试图了解内核同步机制。我试图理解与书中提到的锁定机制有关的一些要点-


”某些情况不需要自旋锁,但确实需要禁用内核抢占。这些情况中最常见的是每个处理器的数据。如果数据对于每个处理器都是唯一的,则可能不需要使用一个锁,因为只有一个处理器可以访问数据。如果没有旋转锁,则内核是抢占式的,新调度的任务可能会访问该变量。

因此,即使这是一台单处理器计算机,也可以通过多个进程伪并行访问该变量。通常,此变量需要自旋锁(以防止在多处理机上真正并发)。但是,如果这是每个处理器的变量,则可能不需要锁定。要解决此问题,可以通过preempt_disable()“

禁用内核抢占。

所以在这里考虑一个多处理器系统- 我了解到,虽然当前进程正在操纵每个cpu变量,但由于SMP可能会安排另一个进程,并尝试操纵相同的每个cpu变量,因此,如书中所述,需要禁用抢占。但是我无法理解的一点是,如果我们仅禁用内核抢占,并且当前进程正在尝试操纵每个CPU数据,并且同时在当前处理器上发生了中断,并且由于该中断尚未被处理,该怎么办?禁用后,CPU停止当前任务并开始执行中断处理程序。现在,该处理程序还希望操作相同的per-cpu变量。那么在这种情况下,变量可能最终包含不一致的数据?

那么这是否意味着如果还可以从中断处理程序访问per-cpu变量,则还需要在当前处理器上禁用该中断?

平台:x86上的Linux

2 个答案:

答案 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 也来了,如果获取自旋锁,它必须等待/自旋。