Appearance
题目
进程 P0 和 P1 的共享变量定义及其初值为
C
boolean flag[2];
int turn = 0;
flag[0] = FALSE;
flag[1] = FALSE;若进程 P0 和 P1 访问临界资源的类 C 伪代码实现如下:
C
void P0() {
while (TRUE) {
flag[0] = TRUE;
turn = 1;
while (flag[1] && (turn == 1));
临界区;
flag[0] = FALSE;
}
}C
void P1() {
while (TRUE) {
flag[1] = TRUE;
turn = 0;
while (flag[0] && (turn == 0));
临界区;
flag[1] = FALSE;
}
}则并发执行进程 P0 和 P1 时产生的情形是( )。
错因
A
把"两进程都举手 + while 等"误以为是死锁式忙等。但本算法(Peterson)两个 while 条件不可能同时成立——turn 只能是 0 或 1,最多让一方等而另一方进。互斥保证是有的,把它否定就错了。
B
承认"不互斥"+"不饥饿"是双错。本算法明确互斥(设计目标就是互斥),且因为 turn 字段会被对方主动让出,两边轮流进,不会饥饿。
C
承认互斥但说会饥饿——但 Peterson 算法的核心特性就是有限等待:即使 P0 迅速 release 后又想再进、和 P1 抢 turn,turn 是被对方设置为对方让位(P0 设 turn=1、P1 设 turn=0),最多让一方再等一轮就一定能进。
总解析
这正是经典的 Peterson 算法——双进程互斥的软件解法。每个进程"先举手 + 让位 + 等":
c
flag[i] = TRUE; // 我想进
turn = j; // 但优先让对方
while (flag[j] && turn == j); // 等:只有对方也想进且这一轮归对方时才等
// 临界区
flag[i] = FALSE; // 离开,放下手互斥性证明(反证):
假设 P0 和 P1 同时进入临界区——意味着两个 while 条件都不成立。
- 对 P0:
flag[1] && turn == 1不成立 → flag[1] = FALSE 或 turn ≠ 1 - 对 P1:
flag[0] && turn == 0不成立 → flag[0] = FALSE 或 turn ≠ 0
两人都举了手 → flag[0] = TRUE 且 flag[1] = TRUE。所以必须 turn ≠ 1 且 turn ≠ 0——这不可能(turn 只取 0 或 1)。矛盾,不可能同时进入。✓ 互斥成立。
无饥饿性证明:
假设 P0 在 while 循环中等:意味着 flag[1] && turn == 1。这时如果 P1 进入临界区且不再进入(出来后 flag[1] = FALSE),P0 立刻能进。
如果 P1 出去后又想进:P1 重新执行 flag[1] = TRUE; turn = 0;——P1 会把 turn 设成 0 让位。这时 P0 的 while 条件 flag[1] && turn == 1 因 turn 变 0 而不成立,P0 立刻能进。
关键:每次进入前都设 turn = 对方 是 Peterson 的核心——它保证如果两人同时争,后到达 turn 赋值的那个让位(写后覆盖了对方的赋值),先 turn 设的人先进。这避免了任何一方被无限制阻塞。
逐项核对:
| 选项 | 互斥? | 饥饿? | 判定 |
|---|---|---|---|
| A | 不互斥 + 饥饿 | — | ✗ |
| B | 不互斥 + 不饥饿 | — | ✗ |
| C | 互斥 + 饥饿 | — | ✗ |
| D | 互斥 + 不饥饿 | — | ✓ |
最终答案是 D。