我一直在搜索有关Peterson算法的信息,但遇到过一些引用,指出它不能满足饥饿要求,而只能满足死锁要求。这是真的?如果可以的话,有人可以详细说明为什么不这样做吗?
彼得森的算法:
flag[0] = 0; flag[1] = 0; turn; P0: flag[0] = 1; turn = 1; while (flag[1] == 1 && turn == 1) { // busy wait } // critical section ... // end of critical section flag[0] = 0; P1: flag[1] = 1; turn = 0; while (flag[0] == 1 && turn == 0) { // busy wait } // critical section ... // end of critical section flag[1] = 0;
该算法使用两个变量,标志和转弯。标志值1表示该进程要进入关键部分。变量turn持有它所在的进程的ID。如果P1不想进入其关键部分,或者如果P1通过将turn设置为0赋予了P0优先级,则为过程P0授予进入关键部分的权限。
正如本杰克逊(Ben Jackson)所怀疑的那样,问题在于通用算法。标准的2进程Peterson算法满足无饥饿性质。
显然,彼得森的原始论文实际上有一个针对N处理器的算法。这是我刚刚用类似C ++的语言写的草图,应该是这种算法:
N
// Shared resources int pos[N], step[N]; // Individual process code void process(int i) { int j; for( j = 0; j < N-1; j++ ) { pos[i] = j; step[j] = i; while( step[j] == i and some_pos_is_big(i, j) ) ; // busy wait } // insert critical section here! pos[i] = 0; } bool some_pos_is_big(int i, int j) { int k; for( k = 0; k < N-1; k++ ) if( k != i and pos[k] >= j ) return true; } return false; }
这是一个死锁场景N = 3:
N = 3
pos[0] = 0
step[0] = 0
pos[2] = 0
step[0] = 2
pos[1] = 0
step[0] = 1
step[0]
j = 1
pos[2] = 1
step[1] = 2
pos[2]
j = 2
参考文献 。所有细节都从Alagarsamy 的论文“ 关于著名的互斥算法的一些神话 ”中获得。显然,Block和Woo在“ 更有效的Peterson互斥算法的泛化 ”中提出了一种改进的算法,该算法确实满足了无饥饿的需求,Alagarsamy后来在“ 具有最佳边界旁路的互斥算法 ”中进行了改进(通过获得最佳的饥饿边界N-1)。 。
N-1