提问人:Kenny Ynnek 提问时间:3/8/2023 最后编辑:JabberwockyKenny Ynnek 更新时间:3/8/2023 访问量:213
我们可以使用一个变量 - 在 Peterson 的解决方案中只转弯吗?
Can we use one variable - turn only in Peterson's solution?
问:
以下是我们讲座中介绍的 Peterson 解决方案:
//P0:
do {
flag[0] = TRUE; turn = 1;
while(flag[1] && turn == 1);
//Critical section
flag[0] = FALSE;
//remainder section
} while(1)
//P1:
do {
flag[1] = TRUE; turn = 0;
while(flag[0] && turn == 0);
//critical section
flag[1] = FALSE;
//remainder section
} while(1)
转弯变量本身不是已经保证了关键部分的要求吗?就像这里似乎没有必要。flag[]
答:
数组为每个进程指定它当前是否对关键部分感兴趣(即它当前是否希望进入它或已经在其中)。出于以下原因,此信息是必需的:flag
假设进程 #0 希望进入关键部分,它必须知道进程 #1 当前是否也对关键部分感兴趣,因为进程 #0 必须根据进程 #1 是否也对关键部分感兴趣而采取不同的行动。
如果进程 #1 对关键部分不感兴趣,则进程 #0 不应等待进程 #1 设置为 ,因为它可能会无限期地等待这种情况发生,这将违反“进度”和“有界等待”要求。相反,在这种情况下,进程 #0 应该只输入关键部分。turn
0
如果进程 #1 对关键部分感兴趣,则进程 #0 应等待进程 #1 对
- 离开关键部分(进程 #1 通过设置为 来指示),或者
flag[1]
false
- 屈服于进程 #0(进程 #1 通过设置为 来指示)。
turn
0
否则,将违反“相互排斥”的要求。
评论
虽然公认的答案很好地解释了 Peterson 的算法,并证明了为什么两者都需要 AND,但这种分析也可以以更“动手”的方式进行,尝试从算法中消除变量,同时保持关键属性互斥、进度和有界等待。turn
flag
flag
只是删除所有语句,就会留下一个明显的问题,例如,如果 P0 设置并开始等待,那么它将无限期等待,除非 P1 设置 .因此,“progress”属性丢失。flag
turn=1
turn==1
turn=0
让我们尝试通过设置为“my”值(P0 为“0”,P1 为“1”)来修复它,并等待直到具有“my”值。这显然需要在退出关键部分时将 设置为“其他”进程的值(否则,“其他”进程可能会在其 -loop 中无限期等待,从而失去“有界等待”属性):turn
turn
turn
while
//P0:
do {
turn = 0;
while(turn != 0);
//Critical section
turn = 1; // Done with critical section, let P1 have a go
//remainder section
} while(1)
//P1:
do {
turn = 1;
while(turn != 1);
//critical section
turn = 0; // Done with critical section, let P0 have a go
//remainder section
} while(1)
然而,这并不能确保“互斥”属性:例如,当 P0 位于其临界部分时,P1 可以愉快地设置并继续其临界部分。turn=1
吸取的教训是:在并发方面要非常小心。到处都有出错的机会,在编码时很难看到,之后更难排除故障。只要有可能,就采用已建立的方法,如彼得森算法,这些方法多年来已经过彻底的分析和优化。
评论
bool
bool
atomic
std::atomic<bool>
turn