测试设置锁机制

2025年3月17日 | 阅读 3 分钟

汇编代码的修改

在锁变量机制中,有时进程会读取锁变量的旧值并进入临界区。由于这个原因,多个进程可能会进入临界区。然而,以下部分的第 1 部分中所示的代码可以用第 2 部分中所示的代码替换。这不会影响算法,但通过这样做,我们可以在一定程度上提供互斥,但不能完全提供。

在更新版本的代码中,锁的值被加载到局部寄存器 R0 中,然后锁的值被设置为 1。

然而,在步骤 3 中,锁的先前值(现在存储在 R0 中)与 0 进行比较。如果为 0,则进程将简单地进入临界区,否则将通过在循环中连续执行来等待。

进程本身立即将锁设置为 1 的好处是,现在进入临界区的进程携带着锁变量的更新值,即 1。

在它被抢占并再次调度的情况下,即使锁变量的当前值如何,它也不会进入临界区,因为它已经知道锁变量的更新值是什么。

第 1 节第 2 节
1. Load Lock, R0
2. CMP R0, #0	
3. JNZ step1
4. store #1, Lock 
1. Load Lock, R0
2. Store #1, Lock
3. CMP R0, #0
4. JNZ step 1 

TSL 指令

然而,上述片段中提供的解决方案在一定程度上提供了互斥,但它不能确保互斥将始终存在。临界区中可能存在多个进程。

如果在执行第 2 节中编写的汇编代码的第一条指令后,进程立即被抢占怎么办?在这种情况下,它将携带锁变量的旧值,并且无论是否知道锁变量的当前值,它都将进入临界区。这可能导致两个进程同时存在于临界区中。

为了摆脱这个问题,我们必须确保在加载锁变量的先前值之后和将其设置为 1 之前,不会发生抢占。如果我们可以将前两条指令合并,这个问题就可以解决。

为了解决这个问题,操作系统提供了一个特殊的指令,称为 **测试设置锁 (TSL)** 指令,它简单地将锁变量的值加载到局部寄存器 R0 中并同时将其设置为 1。

首先执行 TSL 的进程将进入临界区,之后在第一个进程退出之前,没有其他进程可以进入。即使第一个进程被抢占,也没有进程可以执行临界区。

该解决方案的汇编代码如下所示。

  1. TSL Lock, R0
  2. CMP R0, #0
  3. JNZ step 1

让我们根据四个条件来检查 TSL。

  • 互斥
  • TSL 机制保证了互斥,因为进程在设置锁变量之前永远不会被抢占。在特定时间只有一个进程可以将锁变量视为 0,因此保证了互斥。

  • 进度
  • 根据进度的定义,不希望进入临界区的进程不应阻止其他进程进入临界区。在 TSL 机制中,进程只会在希望进入临界区时执行 TSL 指令。如果没有任何进程希望进入临界区,则锁的值将始终为 0,因此 TSL 始终保证进度。

  • 有界等待 (Bounded Waiting)
  • TSL 不保证有界等待。某些进程可能长时间没有机会。我们无法预测进程在一定时间后一定会获得进入临界区的机会。

  • 架构中立性
  • TSL 不提供架构中立性。它取决于硬件平台。TSL 指令由操作系统提供。某些平台可能不提供。因此,它不是架构中立的。


os TSL Instruction