我不知道像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
指令?
答案 0 :(得分:2)
如果另一个执行线程远远落后于标志[other]甚至没有被初始化,会发生什么?
你是对的:Petersen算法要求将标志初始化为零。
如果一个线程在其他线程完成上面的初始化步骤之前进入for循环会怎么样?
面包店算法的definitions表示数字数组的内容必须从0开始。
似乎这些算法都采用了其他一些同步方法,因此其他线程不会在您执行自己的操作时执行操作
事实上,面包店算法令人惊讶地没有这些假设。例如,wikipedia article声明:
每个线程只写自己的存储,只读共享。值得注意的是,该算法不是建立在一些较低级别的“原子”操作之上,例如,比较并交换。原始证明表明,对于对同一存储单元的重叠读写,只有写入必须正确。读操作可以返回任意数字。因此,该算法可用于在缺少同步原语的存储器上实现互斥,例如,在两台计算机之间共享的简单SCSI磁盘。
确实,他们依赖于以初始化值开头的共享值,但根据我的经验,这从未引起过问题。例如,大多数多线程进程从一个线程开始,它会分支其余部分,所以没有问题,所有初始化都是静态完成的,或者在其他线程启动之前完成。