Silberschatz,Galvin和Gagne撰写的《操作系统原理》一书对test_and_set的原子操作具有以下实现方式
boolean test_and_set(boolean *target) {
boolean rv = *target;
*target = true;
return rv;
}
他们声明了一个初始化为0的全局变量锁,并为每个进程使用了以下互斥体实现
do {
while(test_and_set(&lock))
; // do nothing
// critical section
lock = false;
// remainder section
} while(true);
现在,让我们考虑以下情况:进程P0正在实现关键部分,而进程P1停留在while循环中。然后考虑以下执行顺序
//lock = true initially because P0 is in critical section
P1 boolean rv = *target; //rv = true, lock = true
//P0 now completed its critical section and is ready to leave the lock
P0 lock = false //rv = true, lock = false
P1 *target = true; //rv = true, lock = true
P1 return rv; // returns true
因此,事实上,过程P0或任何其他过程无法永远进入关键部分。 那么如何处理这种情况?
答案 0 :(得分:2)
您的描述正确,这样的情况会导致僵局。
但是您缺少的是test_and_set
必须是 atomic 操作。这不是test
后跟set
,而是执行两者的唯一牢不可破的操作。
通常由处理器执行以下指令:1 /禁止乱序执行; 2 /等到处理器的流水线和内存队列为空; 3 /读取寄存器中的内存; 4 /设置记忆字。读/写内存不能被中断,不会发生线程交换,并且禁止其他处理器访问内存。
在风险处理器上,有类似的机制。首先,您执行一个特殊的加载来监视对内存的访问(通常称为load locked
),然后执行一个特殊存储,如果对存储位置(store conditional
)进行了任何访问,该存储都会失败。
这样,可以确定在test_and_set
期间只有一个线程可以访问内存,并且不会发生您描述的情况。
//lock = true initially because P0 is in critical section
P1 boolean rv = *target; //rv = true, lock = true
//P0 now completed its critical section and is ready to leave the lock
// BUT P0 MUST WAIT THE COMPLETION OF THE TAS.
// NO THREAD SWAP CAN HAPPEN AND ACCESS TO *target IS LOCKED
// DELAYED UNTIL END OF TAS P0 lock = false //rv = true, lock = false
P1 *target = true; //rv = true, lock = true
P1 return rv; // returns true
//NOW WE CAN DO
P0 lock = false //rv = true, lock = false
// AND LOCK IS PROPERLY UNSET
// ON NEXT ITERATION OF THE SPINLOCK WHILE, P1 WILL GET IT.