6

通读Understanding the Linux kernel (Bovet & Cesati),内核同步一章后,自旋锁获取代码归结为:

1: lock:
   btsl    $0, slp
   jnc     3
2: testb   $1, slp
   jne     2
   jmp     1
3: 

现在我最初认为嵌套循环似乎很浪费,你可以实现类似的东西:

1: lock:
   btsl    $0, slp
   jc      1

这会简单得多。但是,我明白他们为什么这样做了,因为它lock会影响其他 CPU,而且它们的时间btsl比简单的testb.

我无法理解的一件事是随后释放自旋锁。该书指出,它产生以下内容:

   lock:
   btrl    $0, slp

我的问题基本上是为什么?在我看来,lock/mov-immediate组合更快。

您不需要将旧状态设置为进位标志,因为遵循内核无错误的规则(假设在所述内核内部的许多其他地方),旧状态将为 1(您不会如果您还没有获得它,请尝试释放它)。

而且 amov比 a 快得多btrl,至少在 386 上是这样。

那么我错过了什么?

以后芯片上这些指令的时间是否发生了变化?

自从本书出版以来内核是否已更新?

这本书是完全错误的(或显示了简化的说明)吗?

我是否错过了一些其他方面,涉及更快的指令不满足的 CPU 之间的同步?

4

1 回答 1

10

嗯,Understanding the Linux Kernel老了。自编写以来,Linux 内核已更新为使用所谓的票据自旋锁。锁基本上是一个 16 位的数量,分为两个字节:让我们调用一个Next(如分配器中的下一张票)和另一个Owner(如柜台上的“Now Serving”号码)。自旋锁被初始化,两个部分都设置为零。锁定记录自旋锁的值,并以原子方式递增 Next。如果递增前Next的值等于Owner,则说明已经获得锁。否则,它会旋转直到 Owner 增加到正确的值等等。

相关代码在asm/spinlock.h中(对于 x86)。解锁操作确实比书上说的要快得多,也简单得多:

static __always_inline void __ticket_spin_unlock(arch_spinlock_t *lock)
{
    asm volatile(UNLOCK_LOCK_PREFIX "incb %0"
         : "+m" (lock->slock)
         :
         : "memory", "cc");
}

因为inc大约比 . 快 8 或 9 倍btr

希望这可以帮助; 如果没有,我很乐意深入挖掘。

于 2011-01-19T15:41:04.390 回答