每个进入临界区的进程的权限只能被另一个进程赋予
int turn=0;
//进程P0
do{
while(turn!=0);//进入区
P0代码;//退出区
turn=1;//退出区
}while(true)
//进程P1
do{
while(turn!=1);//进入区
P1代码;//临界区
turn=0;//退出区
}while(true)
严格轮换,实现了互斥访问
违反了空闲让进的原则:比如turn=1时,临界区空,但P1无法进入
进入之前看有没有其他进程要进入,没有则将自己的状态置为true
boolean flag[2]={false,false}//该全局变量标志临界区空闲与否
//进程P0
do{
while(flag[1]);//进入区
flag[0]=true;//进入区
P0代码;//临界区
flag[0]=false;//退出区
}while(true)
//进程P1
do{
while(flag[0]);//进入区
flag[1]=true;//进入区
P1代码;//临界区
flag[1]=false;//退出区
}while(true)
违反了忙则等待原则:假设CPU先将时间片分给P0,然后P0判断flag[1]=false跳出循环向下执行,这时CPU又将时间片分给 P1,P0尚未执行到置flag[0]=true;P1判断flag[0]=false跳出循环向下执行,两者都将进入临界区
注意:while(flag[1]);这一句表明:当flag[1]=true时停在这一句,flag[1]=false时跳出循环执行下一句,P0即进入临界区
先亮明状态,再循环等待
boolean flag[2] = {false, false};//共享的全局变量
//进程P0
do {
flag[0] = true; //进入区
while (flag[1]) ;//进入区
进程P0的临界区代码; //临界区
flag[0] = false; //退出区
进程P0的其它代码 //剩余区
} while (true)
//进程P1
do {
flag[1] = true; //进入区
while (flag[0]) ;//进入区
进程P1的临界区代码; //临界区
flag[1] = false; //退出区
进程P1的其它代码 //剩余区
} while (true)
违反了空闲让进原则:CPU先将时间片分给P0,然后P0置flag[0]=true,这时CPU又将时间片分给 P1,P1置flag[1]=true;那么接下来两者都在while循环处等待对方清零,都无法进入临界区,形成死锁
预先表明想进入临界区,但为了防止死锁,在进入临界区前会延迟一段时间
boolean flag[2] = {false, false};//共享的全局变量
//进程P0
do {
flag[0] = true;
while (flag[1]) {
flag[0] = false;
<随机延迟一小段时间>;//谦让
flag[0] = true;
}
进程P0的临界区代码; //临界区
flag[0] = false; //退出区
进程P0的其它代码 //剩余区
} while (true)
//进程P1
do {
flag[1] = true;
while (flag[0]) {
flag[1] = false;
<随机延迟一小段时间>;//谦让
flag[1] = true;
}
进程P1的临界区代码; //临界区
flag[1] = false; //退出区
进程P1的其它代码 //剩余区
} while (true)
可能会活锁,过分谦让,长时间僵持:CPU先将时间片分给P0,然后P0置flag[0]=true,这时CPU又将时间片分给 P1,P1置flag[1]=true;接下来CPU先将时间片分给P0,P0发现flag[1]=true;进入while循环,先将flag[0]清零,再挂起一段时间,重新置位flag[0],查看flag[1]是否仍为1,若是则继续清零等待,重复这个过程,监听flag[1]的变化;同理,P1可能会与P0默契地进行同样的活动,两者同时监听,同时挂起,形成活锁,可能随时间自动解除
由于前一种算法活锁的原因是只监听了对方的flag,这时添加一个只能由对方改变的信息turn即可
boolean flag[2] = {false, false}; //共享的全局变量
int turn = 1; //共享的全局变量
//进程P0
do {
flag[0] = true; //进入区
while (flag[1]) {
if (turn == 1) {
flag[0] = false;
while (turn == 1) ; //等待
flag[0] = true;
}
} //进入区
进程P0的临界区代码; //临界区
turn = 1;
flag[0] = false; //退出区
进程P0的其它代码 //剩余区
} while (true)
//进程P1
do {
flag[1] = true; //进入区
while (flag[0]) {
if (turn == 0) {
flag[1] = false;
while (turn == 0) ; //等待
flag[1] = true;
}
} //进入区
进程P1的临界区代码; //临界区
turn = 0;
flag[1] = false; //退出区
进程P1的其它代码 //剩余区
} while (true)
在预先表明态度+谦让的基础上改进了谦让机制:
P1在退出临界区时会置turn=0;P0退出临界区会将turn置为1
这样一来,可以在监听对方flag时知道对方是否已经退出临界区,而不是等待一段随机时间,我认为这时重新尝试将自己的flag置为true是更好的做法,不会产生活锁
与dekker算法的区别:不是在退出时而是在进入前将turn改变
boolean flag[2] = {false, false}; //共享的全局变量
int turn; //共享的全局变量
//进程P0
do {
flag[0] = true; //进入区
turn = 1; //进入区
while (flag[1] && turn == 1) ; //进入区
进程P0的临界区代码; //临界区
flag[0] = false; //退出区
进程P0的其它代码 //剩余区
} while (true)
进程P1
do {
flag[1] = true; //进入区
turn = 0; //进入区
while (flag[0] && turn == 0) ; //进入区
进程P1的临界区代码; //临界区
flag[1] = false; //退出区
进程P1的其它代码 //剩余区
} while (true)
假设P0进程先置自己的flag为true,改变turn=1,此时有一个while循环,当P1的flag=false时,说明P1还没有运行到置flag=true的行,可以继续进入临界区,或当turn=0时,这时说明P1执行后转而执行P0,P0此时在turn行,但P0无法进入临界区,因为此时flag[0]=true,而此时P0可以无视flag[1]=true的条件而继续进入临界区