彼得森的算法如何在不做出不切实际假设的情况下工作?

时间:2017-06-23 15:29:42

标签: multithreading algorithm

我不知道像Peterson和Lamport这样只有软件的关键部分算法是如何运作的。

维基百科列出了彼得森的伪代码:

flag[me] = true;
turn  = other;
while (flag[other] == true && turn == 1)
     {
         // busy wait
     }
 // critical section
 // end of critical section
 flag[me] = false;

在我看来,这在实践中无法发挥作用。如果另一个执行线程远远落后于flag[other]甚至没有初始化,会发生什么?

对于面包店算法:

   Entering[i] = true;

  Number[i] = 1 + max(Number[1], ..., Number[NUM_THREADS]);

  Entering[i] = false;

  for (integer j = 1; j <= NUM_THREADS; j++) {

      // Wait until thread j receives its number:

      while (Entering[j]) { /* nothing */ }

      // Wait until all threads with smaller numbers or with the same

      // number, but with higher priority, finish their work:

      while ((Number[j] != 0) && ((Number[j], j) < (Number[i], i))) { /* nothing */ }

  }

如果一个线程在其他线程完成上面的初始化步骤之前进入for循环,该怎么办?我错过了什么吗?

维基百科甚至说:

  

该算法满足解决该问题的三个基本准则   临界区问题,提供变量的变化   turn,flag [0]和flag [1]立即和原子地传播

这不是一个不合理的假设吗?看起来这些算法都假设了一些其他的同步方法,所以其他线程不会在你自己的操作中执行操作,但是如果我们已经有了,那么并不是所有这些算法都应该给你,因为当你没有可以锁定其他人的硬件时,比如LOCK指令?

1 个答案:

答案 0 :(得分:2)

  

如果另一个执行线程远远落后于标志[other]甚至没有被初始化,会发生什么?

你是对的:Petersen算法要求将标志初始化为零。

  

如果一个线程在其他线程完成上面的初始化步骤之前进入for循环会怎么样?

面包店算法的definitions表示数字数组的内容必须从0开始。

  

似乎这些算法都采用了其他一些同步方法,因此其他线程不会在您执行自己的操作时执行操作

事实上,面包店算法令人惊讶地没有这些假设。例如,wikipedia article声明:

  

每个线程只写自己的存储,只读共享。值得注意的是,该算法不是建立在一些较低级别的“原子”操作之上,例如,比较并交换。原始证明表明,对于对同一存储单元的重叠读写,只有写入必须正确。读操作可以返回任意数字。因此,该算法可用于在缺少同步原语的存储器上实现互斥,例如,在两台计算机之间共享的简单SCSI磁盘。

确实,他们依赖于以初始化值开头的共享值,但根据我的经验,这从未引起过问题。例如,大多数多线程进程从一个线程开始,它会分支其余部分,所以没有问题,所有初始化都是静态完成的,或者在其他线程启动之前完成。