需要帮助来了解使用test_and_set实现互斥锁

时间:2019-03-08 14:51:05

标签: concurrency operating-system locking mutual-exclusion test-and-set

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或任何其他过程无法永远进入关键部分。 那么如何处理这种情况?

1 个答案:

答案 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.