4

我是 Linux 新手,正在阅读 Rubini & Corbet 的 Linux 设备驱动程序书。我对与以下内容相关的一项声明感到困惑spinlocks;这本书说

如果一个非抢占式单处理器系统曾经在锁上自旋,它将永远自旋;没有其他线程能够获得 CPU 来释放锁。出于这个原因,没有启用抢占的单处理器系统上的自旋锁操作被优化为什么都不做,除了那些改变 IRQ 屏蔽状态的操作。

书中进一步指出

内核抢占情况由自旋锁代码本身处理。每当内核代码持有自旋锁时,相关处理器上的抢占都将被禁用。甚至单处理器系统也必须以这种方式禁用抢占以避免竞争条件。

问题:在单处理器系统上,如果内核抢占在内核代码(代表用户进程执行)持有自旋锁时被禁用,那么另一个进程如何有机会运行并因此尝试获取自旋锁?当内核代码持有自旋锁时,为什么 Linux 内核会禁用内核抢占?

4

4 回答 4

9

第一个问题的答案是第二个问题背后的原因。

内核获取的自旋锁可以通过关闭抢占来实现,因为这样可以确保内核完成其临界区而没有其他进程的干扰。关键是在内核释放锁之前,另一个进程将无法运行。

没有理由必须以这种方式实施;这只是实现它的一种简单方法,并防止任何进程在内核持有的锁上旋转。但是这个技巧只适用于内核已经获得锁的情况:用户进程不能关闭抢占,如果内核正在旋转(即它试图获得一个自旋锁但另一个进程已经持有它)最好离开抢占上!否则系统将挂起,因为内核正在等待一个不会释放的锁,因为持有它的进程无法释放它。

内核获取自旋锁是一种特殊情况。如果用户级程序获得自旋锁,则不会禁用抢占。

于 2013-08-15T15:09:20.253 回答
1

进程 A 和进程 B 都访问相同的数据,因此您定义了一个 SPIN LOCK。如果 A 持有锁但保持启用抢占。那么 A 可能会被调度出去,而 B 有机会运行。如果 B 试图获得锁。B将旋转并浪费cpu。

自旋锁旨在提高效率并保护小而快的关键区域。所以旋转块禁用抢占。如果您想要锁定但保持启用抢占。你可以使用互斥锁。

当进程 A 释放锁时,再次启用抢占。所以其他进程有机会运行。在此之前,只能运行硬件中断和软件中断。

于 2019-10-24T02:40:45.283 回答
0

每当内核代码持有自旋锁时,仅在相关处理器上禁用抢占。这意味着如果这是一个 SMP 系统,则仅在当前处理器上禁用抢占,同时运行的其他处理器仍然可以自由获取该锁并忙于等待。因此,在持有自旋锁后休眠会导致死锁。

而在单处理器系统的情况下,必须禁用抢占,因为如果另一个进程持有锁,它将一直忙于等待并且不允许第一个进程释放锁。

于 2020-12-24T07:32:07.817 回答
0

自旋锁仅在单处理器上禁用抢占。因此,在单个处理器的情况下:假设调度程序的队列中有以下进程:P1、P2、P3、P4 - 都请求自旋锁 L。所有这些都将在排队时获得锁(即 P1 后跟P2等)

在单处理器系统上禁用抢占的原因是: 如果不是:P1 持有锁并在一段时间后被调度。现在 P2 开始执行,假设请求同一个自旋锁。由于 P1 没有释放自旋锁,P2 必须自旋并且什么也不做。所以浪费了P2的执行时间。让 P1 释放锁然后允许它被抢占更有意义。此外,由于没有其他处理器,只需禁止抢占,我们就知道永远不会有另一个进程在另一个处理器上并行运行并访问相同的临界区。

同样,如果您的关键部分与中断共享,我们需要在该处理器上本地禁用中断。在中断的情况下,它们永远不会被安排出来。因此,中断永远不会请求已被它中断的进程持有的锁,这一点很重要。这样的进程永远不会在任何其他处理器上运行,因为它没有被调度出来,因此它永远不会有机会释放锁。因此,中断处理程序永远不会完成导致死锁。因此,在这种情况下,我们总是禁用处理器上的本地中断。

于 2019-10-22T19:13:38.187 回答