进程互斥需要遵循的四个原则:
空闲让进,忙则等待,有限等待,让权等待
单标志法
设置一个标志表示当前允许进入临界区的进程号:
int turn =0;
p0进程:
while(turn!=0);//判断进程号是否是0,如果不是的话就卡在while循环这里。
critical section//进入临界区
turn=1;
remainder section//离开临界区
p0进程:
while(turn!=1);//判断进程号是否是0,如果不是的话就卡在while循环这里。
critical section//进入临界区
turn=0;
remainder section//离开临界区
缺点:如果turn 的初值是0,但是P1先上处理机,就会一直卡在循环的地方。可以实现“同一时刻只允许一个进程访问临界区”,但是无法满足空闲让进的原则。
双标志先检查法
先检查是否有访问临界区的意愿,有的话再上锁。
p0:
while(flag[1]);//如果p1进程想进入临界区,那么p0进程就必须等在这里(1)
flag[0]=ture;(2)
critical section;(3)
flag[0]=false;(4)
remainder section;
p1:
while(flag[0]);//如果p0进程想进入临界区,那么p1进程就必须等在这里(5)
flag[1]=ture;(6)
critical section;(7)
flag[1]=false;(8)
remainder section;
但是如果程序执行的顺序是:(1)(5)(2)(6)(3)(7),那么两个进程会同时进入临界区,无法满足忙则等待的原则。
双标志后检查法
上面是先检查对方的意愿,再表达自己的意愿,后检查法则是先表达自己的意愿,再检查对方的意愿。
p0:
flag[0]=ture;(1)
while(flag[1]);(2)
critical section;(3)
flag[0]=false;(4)
remainder section;
p1:
flag[1]=ture;(5)
while(flag[0]);(6)
critical section;(7)
flag[1]=false;(8)
remainder section;
但是如果程序执行的顺序是(1)(5)(2)(6),那么两个进程就会互相谦让,谁都无法执行,不满足空闲让进和有限等待的原则,会产生“饥饿”现象。
peterson算法
结合单标志法、双标志法,主打一个孔融让梨的思想。
bool flag[2];
int turn =0;
p0:
flag[0]=ture;
turn=1;//如果p0进程想进临界区,那么它会先允许p1进入临界区
while(flag[1]&&turn==1);//如果p1也想进入临界区,那么p0就必须等待,否则可以进入临界区
critical section;
flag[0]=false;
remainder;
p1:
flag[1]=ture;
turn=0;//如果p1进程想进临界区,那么它会先允许p0进入临界区
while(flag[0]&&turn==0);//如果p0也想进入临界区,那么p1就必须等待,否则可以进入临界区
critical section;
flag[0]=false;
remainder;
peterson算法符合空闲让进、忙则等待、有限等待的原则,但是仍未满足让权等待(无法访问临界区则下处理机)的原则,并且在乱序执行的CPU上不一定正确。