如果我在下面的代码片段中跳过 waiting[i] = false 会发生什么?

What will happen if I skip waiting[i] = false In the following snippet of code?

下面的代码是为了解决临界区问题而设计的。假设有 N 个进程正在修改其临界区中的公共数据结构。

这些是使用的数据结构:

boolean waiting[n];
boolean lock;

这里是 testAndSet() 函数,假设由于硬件支持而自动执行。

boolean TestAndSet(boolean *target) 
{
    boolean rv = *target;
   *target = TRUE;
    return rv;
}

// 下面的代码确保互斥

do {
    waiting[i] = TRUE;
    key = TRUE;

    while (waiting[i] && key)
        key = TestAndSet(&lock);

    waiting[i] = FALSE;  //what if I skip this??

    // critical section

    j = ( i + 1) % n ;
    while((j != i) && ! waiting[j])
    {
       j = (j + 1) % n ;
    }
    if (j == i)
       lock = FALSE;
    else
       waiting[j] = FALSE;

   //remainder section

   }while (TRUE);

如果您跳过“... = FALSE”行,这意味着您仍在第一个 while 循环(对于特定 i)中等待获取锁(临界区),并且会破坏 "round robin" 在第二个 while 循环中访问临界区。

删除那条线可能会破坏整个事情。它上面的两行是一个 while 循环,它可能会在两种情况之一中终止——要么 waiting[i] 变成假,要么 key 变成假(或者两者都 "simultaneously") .如果循环由于 key 为假而终止,那么 waiting[i] 可能仍然为真,因此您将进入一种情况,您既持有锁又同时认为您仍在等待锁,这可能违反了后续 while 循环的先决条件...

你确实需要在第一个 while 之后缩进该行。

"// critical section" 下面的内容将解锁下一个等待访问的任务,或者如果没有人在等待则释放锁。

如果您不清除您的等待标志,那么另一个已经获得锁的任务(大概 运行使用相同的代码来访问受保护的内存)会认为您仍在等待并且会清除您的等待标志以允许您 运行(假设您正处于循环中,检查 TestAndSet,这是您的等待标志唯一为真的地方)。它保持锁定标志设置,因为它只是有效地将锁定传递给您。但是,如果您的代码实际上已经从该点继续前进而没有将值设置为 false,那么如果您不将等待标志设置为 True 就无法返回到 TestAndSet,并且由于 lock 也保留为 true,因此该任务无法执行运行,其他任务没有 运行ning,因为下一个任务没有得到批准(或者锁定没有设置为 false),整个系统现在都崩溃了向上。

我想我明白了。整个混乱是由包含整个代码的 do while() 循环造成的。而不是这个做 while() 事情,如果这些就像一些函数代表一个过程,比如

function(int i)
{
  waiting[i] = TRUE;
  key = TRUE;

  while (waiting[i] && key)
    key = TestAndSet(&lock);

  waiting[i] = FALSE;  //what if I skip this??

  // critical section

  j = ( i + 1) % n ;

  while((j != i) && ! waiting[j])
  {
    j = (j + 1) % n ;
  }

  if (j == i)
   lock = FALSE;
  else
   waiting[j] = FALSE;

  //remainder section
}

假设一个函数被调用时 i = 3(比如进程 i3,N = 5)。并且这个进程 i3 永远不会再次执行然后不设置 waiting[3]=false 将以死锁情况结束。由于进程 i4 可能认为进程 i3 想要 运行 因此它将通过设置 waiting[3] = false 并且不释放锁来结束