Silberschatz,Galvin和Gagne的“操作系统原理”一书包含有关同步章节中TestAndSet()指令的以下定义:
boolean TestAndSet(boolean *target) {
boolean rv = *target;
*target = TRUE;
return rv;
}
使用上述指示实现互斥也如下:
do {
while(TestAndSetLock(&lock))
; // do nothing
// critical section
lock = FALSE;
// remainder section
} while(TRUE);
现在,如果没有条件将目标设置为TRUE,如何实现互斥?
考虑以下情况,进程P0将共享变量 lock 设置为TRUE并进入其临界区。另一个进程P1在上面的while循环中调用TestAndSet(),它返回TRUE(因为P0具有锁定),同时无条件地将 lock 设置为FALSE。第二次在while循环中调用TestAndSet()它将返回FALSE并且P1进入其临界区,即使P0处于其临界区。然后违反了相互排斥。
我做了一些搜索,偶然发现了Mithun Acharya和Robert Funderlic(北卡罗来纳州立大学CS系)的论文,其中包含以下TestAndSet()的替代定义:
boolean Test-and-Set(boolean target)
begin
if(target == false):
target = true;
return target;
end
这对我来说更有意义,我把它包括在内进行比较,也因为该论文将Silberschatz的书列为其参考书之一。
我只是不明白我在教科书(我先提供的那本书)中找到的定义如何用于实现互斥,任何人都可以帮忙吗?
答案 0 :(得分:17)
这是一种直观地考虑原子TestAndSet的方法。
线程在进入关键区域之前使用它。只有两种情况:
因此,另一个线程位于关键区域,因此* target(TRUE)反映了该值应该是什么;或者“我”现在进入这个关键区域,所以将* target设置为TRUE。
答案 1 :(得分:6)
显示的实现可以更清晰地写成:
while(TestAndSet(&lock))
{
// spin in this loop until TestAndSet returns false
}
do_critical_section_stuff();
lock = FALSE;
// We've now left the critical section
我认为OP错误解释为:
while(TestAndSet(&lock))
{
lock = FALSE;
}
do_critical_section_stuff();
由于显而易见的原因无法正常工作。
答案 2 :(得分:4)
啊我也有这个问题。让我分享一下我的理解。
最初*目标将为FALSE。(这是给定的)。
P确实需要通过while(TestAndSetLock(&lock)) ; // do nothing
获取锁定并进入关键部分。 (获得锁定只是一个假设的事情,如果它可以通过while循环然后它有锁定)
有人拥有锁定意味着目标 TRUE , 锁定是免费的目标是 FALSE 。 所以一开始就是这样,
P1(第一个调用该函数会很幸运),他看到目标为FALSE并将其设置为true并返回FALSE,这导致它避免while循环等待。
现在目标是TRUE。其他事实是 TestAndSet(boolean_ref lock) 将返回被调用的值, 并且 TestAndSet(boolean_ref lock)将始终将目标设置为 TRUE 所以有人必须在其他地方将目标设置为FALSE(所以带锁的人可以将其设置为FALSE )
其他P将会看到目标为TRUE,当调用TestAndSet(boolean_ref lock)
时,它将始终返回TRUE,直到P1将目标设置为false。
答案 3 :(得分:3)
您最初引用的TestAndSet函数仅在target为false时执行。即线程阻塞,直到target为false。我没有那本教科书,但我确信它已在文中的某处提到过。
请注意,TestAndSet是一个“原子”函数,必须在OS的最低级别(甚至是CPU的指令集)中实现。如果它在用户应用程序中实现,则测试和集合之间可能会发生上下文切换,从而导致损坏。
澄清:我只确定当target为false时执行该函数的事实,因为某些地方必须是阻塞的比较操作。有两种类型的TestAndSet - 一种仅在目标设置为True(阻塞)时返回,另一种可以返回False,即立即返回(一次将启用另一个线程轮询)。我假设你引用的那个是阻塞的,因为它似乎在开始执行后立即返回,这意味着“IF”语句由较低级别的机制执行,例如CPU或OS内核。
答案 4 :(得分:1)
要使用testAndset方法,我们从一个名为Lock的变量开始,该变量设置为false:
HdwareData lock = new HdwareData(false);
答案 5 :(得分:0)
通过查看TestAndSet(& lock)互斥的实现,可以有把握地说,只要TestAndSet返回true,进程(P)就不会进入其临界区。该过程将继续在其循环条件下执行,直到它(条件)失败。
只要另一个进程锁定了资源,条件就会成功(TestAndSet将返回true)。当另一个进程锁定资源时,lock的值为true。一旦其他进程释放其对资源的保留,通过设置lock = false,TestAndSet将返回false。
当TestAndSet返回false时,while循环的条件失败,因此进程P进入其临界区。
TestAndSet是一个原子操作,即它在没有中断的情况下执行。这样做是为了防止锁定的竞争条件。
答案 6 :(得分:0)
非线性地思考。你在Silberchatz提供的实现 testAndSet()函数的定义中指出了三个问题:
(1)您正确地声明 target 无条件地设置为TRUE,并且(错误地)实现了这是一个问题。
(2)为了解决(1)中的问题(不存在),建议在将目标设置为TRUE之前对其进行测试。
(3)最后,您通过实现互斥的块(实际上并未发生这种情况)无条件地将 result 设置为FALSE这一事实表明了您的担忧。
我会尽力澄清这些问题。最初,请注意函数 TestAndSet()的第一件事是将 target 的值复制到 rv ,然后才将目标复制无条件设置为TRUE。现在,问题是:如果 target 最初为FALSE, TestAndSet()将 target 设置为TRUE并返回FALSE,因此进程可以进入关键部分。如果原始目标值为TRUE,则无论如何它都设置为TRUE(这不会造成任何伤害)并且 TestAndSet()返回TRUE,因此进程无法进入关键区域。因此,将 target 无条件地设置为TRUE不是问题,问题(1)证明不存在。
关于问题(2),一旦上面说明无条件地将 target 设置为TRUE是无害的,就不需要事先测试它的值。
问题(3)也不存在,因为结果实际上没有真正无条件地设置为FALSE。我的意思是,它是,但只有在此之后关键区域已由该过程处理;即,当不再需要相互排斥时。该进程必须在离开临界区时将目标设置为FALSE(在退出临界区后不应阻止任何其他进程)。在处理关键部分后必须释放锁!
答案 7 :(得分:0)
在您的问题中考虑以下突出显示的部分:
考虑以下情况,进程P0将共享变量锁设置为TRUE并进入其临界区。另一个进程P1在上面的while循环中调用TestAndSet(),它返回TRUE(因为P0具有锁定) ,同时无条件地将锁定设置为FALSE 。第二次在while循环中调用TestAndSet()它将返回FALSE并且P1进入其临界区,即使P0处于其临界区。然后违反了相互排斥。
P1(或任何过程),无论锁是True还是False,都不会将lock的值设置为False。
如果锁定值为False,则进入临界区并将其值设置为True,从而获取锁定。
如果锁定值为True,则不执行任何操作(将其值设置为True,从而不更改它)并等待锁定值变为False(当具有锁定的进程完成执行时会发生这种情况)其关键部分)。