使用TestAndSet()指令进行互斥

时间:2009-07-20 08:10:37

标签: synchronization operating-system mutual-exclusion

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的书列为其参考书之一。

我只是不明白我在教科书(我先提供的那本书)中找到的定义如何用于实现互斥,任何人都可以帮忙吗?

8 个答案:

答案 0 :(得分:17)

这是一种直观地考虑原子TestAndSet的方法。

线程在进入关键区域之前使用它。只有两种情况:

  1. 正在保持锁定(* target为TRUE):返回TRUE且* target保持为TRUE
  2. 未保留锁定:返回FALSE,* target设置为TRUE
  3. 因此,另一个线程位于关键区域,因此* 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 。 所以一开始就是这样,

enter image description here

enter image description here

P1(第一个调用该函数会很幸运),他看到目标为FALSE并将其设置为true并返回FALSE,这导致它避免while循环等待。

enter image description here

enter image description here

现在目标是TRUE。其他事实是 TestAndSet(boolean_ref lock) 将返回被调用的值, 并且 TestAndSet(boolean_ref lock)始终将目标设置为 TRUE 所以有人必须在其他地方将目标设置为FALSE(所以带锁的人可以将其设置为FALSE

其他P将会看到目标为TRUE,当调用TestAndSet(boolean_ref lock)时,它将始终返回TRUE,直到P1将目标设置为false。

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

我从This site, you can download it from here

找到了这个漂亮的图解说明

答案 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(当具有锁定的进程完成执行时会发生这种情况)其关键部分)。