本文概述
汇编代码中的修改
在锁变量机制中, 有时Process会读取锁变量的旧值并进入关键部分。由于这个原因, 可能有多个线程进入关键部分。但是, 下一节第一部分中显示的代码可以替换为第二部分中显示的代码。这不会影响算法, 但是通过这样做, 我们可以设法在某种程度上但并非完全提供互斥。
在更新的代码版本中, 将Lock的值加载到本地寄存器R0中, 然后将lock的值设置为1。
但是, 在第3步中, 将锁的先前值(现在已存储到R0中)与0进行比较。如果为0, 则线程将简单地进入临界区, 否则将在循环中连续执行以等待。
通过进程本身将锁立即设置为1的好处是, 现在进入关键部分的进程将携带锁变量的更新值1。
在被抢占和再次调度的情况下, 无论锁变量的当前值如何, 它都不会进入临界区, 因为它已经知道锁变量的更新值是什么。
第一节 | 第二节 |
---|---|
1.负载锁定, R0 2. CMP R0, #0 3. JNZ步骤1 4.存放#1, 锁 | 1.负载锁定, R0 2.商店#1, 锁 3. CMP R0, #0 4. JNZ步骤1 |
TSL指令
但是, 以上部分中提供的解决方案在某种程度上提供了互斥, 但并不能确保互斥将始终存在。关键部分可能有多个线程。
如果在执行第2节中编写的汇编代码的第一条指令后立即抢占了该进程怎么办?在这种情况下, 它将随身携带锁变量的旧值, 并且无论知道锁变量的当前值如何, 都会进入临界区。这可能会使这两个线程同时出现在关键部分中。
要解决此问题, 我们必须确保在加载锁变量的先前值之后以及将其设置为1之前, 一定不要发生抢占。如果能够合并前两个, 就可以解决该问题。说明。
为了解决该问题, 操作系统提供了一条称为”测试设置锁定”(TSL)指令的特殊指令, 该指令仅将锁定变量的值加载到本地寄存器R0中并同时将其设置为1。
首先执行TSL的线程将进入关键部分, 此后没有其他线程可以进入, 直到第一个线程出来。即使在抢占第一个进程的情况下, 也没有任何进程可以执行关键部分。
解决方案的汇编代码如下所示。
- TSL锁, R0
- CMP R0, #0
- JNZ步骤1
让我们根据这四个条件检查TSL。
互斥
在TSL机制中保证了互斥, 因为永远不会在设置锁变量之前抢占一个进程。在特定时间只有一个进程可以将lock变量视为0, 这就是为什么保证互斥的原因。
进展
根据进度的定义, 不想进入关键部分的线程不应阻止其他线程进入。在TSL机制中, 仅当进程想要进入关键部分时才执行TSL指令。如果没有进程不想进入关键部分, 则锁的值将始终为0, 因此在TSL中始终保证进度。
有限的等待
TSL中不能保证有界等待。某些线程可能没有那么久的机会。我们无法预测某个线程一定会在一定时间后进入关键部分。
建筑中立
TSL不提供架构中立性。这取决于硬件平台。 TSL指令由操作系统提供。某些平台可能不提供该功能。因此, 这不是建筑上的自然现象。
评论前必须登录!
注册