Peterson算法是实现进程互斥访问临界区的一种方法,避免了单标志法必须交替访问的限制,以及双标志法后检验的“饥饿”问题。
Peterson算法实现如下:
Pi进程:
flag[i] = TRUE; turn = j;
while(flag[j] && turn == j);
// 访问临界区
flag[i] = FALSE;
// 剩余区
Pj进程:
flag[j] = TRUE; turn = i;
while(flag[i] && turn == i);
// 访问临界区
flag[j] = FALSE;
// 剩余区
对于Pi进程:
flag[i] = TRUE将自身的访问位置为1,turn = j 向对方发出访问请求;
while中的循环条件即阻塞条件为,若对方需要访问且对方未应答访问请求。
对于阻塞条件我们可以这样理解,访问位置为1即自己想要访问临界区,然后向对方发出访问请求。若此时对方根本不想访问,那么不会被阻塞直接访问临界区,此时不会发生异常;
若此时对方将访问位已经置为1,那么对方可能准备访问临界区或正在访问临界区:
- 若对方正在访问临界区,那么此时对方不会应答自己的请求,则被阻塞;
- 若对方准备访问临界区,访问前需要收到我方应答,此时先发送请求的一方必定会收到应答,即可以访问临界区,那么另一方因为请求后对方已经进入临界区,得不到应答,必须等对方退出临界区,将访问位置0才能访问。
在这样的机制下,双方实现了对临界区的互斥访问。
试想,如果交换turn赋值语句和flag赋值语句的位置,能否实现互斥访问临界区?
答案是否定的。
如果交换位置,意味着在没有访问意愿的情况下先发送访问请求。此时若我方得到应答却突然阻塞,那么对方虽然不会再收到应答,但检测到我方根本不想访问,直接进入临界区。而当对方处于临界区时我方被唤醒,即使对方的访问位为1,我方已经获得过应答,也可以访问临界区,则访问出现冲突。