引入Dekker互斥算法解决的是多进程访问一个临界区的保护问题和“after you”问题。
我们首先来看,两个进程访问一段临界区的互斥问题:
//P进程如下:
pturn = true;
while(qturn);
//临界区的资源
pturn = false;
//q进程如下:
qturn = true;
while(pturn);
//临界区的资源
qturn = false;
pturn=true表示P进程想访问临界区,qturn = true表示Q进程想要访问临界区。那么这两个进程对于临界区的访问会有什么问题呢?假设P进程首先开始,pturn被置为true。这时候来了一个中断,然后CPU就把P进程切下去了,换Q进程上CPU。同样,把qturn置为true,然后进入循环,此时进入了死循环,因为Q进程发现pturn = =true也就是Q进程知道了P进程也想进入临界区,所以循环一直进行,直到时间片用完,Q被切下CPU,换P进程来上CPU。同样P发现qturn==true,也就是P进程知道了Q也想上临界区,所以P进程也陷入死循环,这样两个都想进入临界区的进程,都互相谦让不进入临界区,这就是一个“after you”的问题。
那么怎么解决这个问题呢?答案就是DEKKER算法,相当于在之前这个算法的基础上做了一个改进,加上了一个turn变量,表示发现“after you”问题之后,由turn决定谁上临界区,谁不上。那么DEKKER算法如下:
//P进程
pturn = true;
while(qturn){
if(turn == 2){//如果发现了互相谦让,且turn==2表示在这种情况下Q先访问临界区
pturn = false;//表示先放弃自己想访问临界区的意愿
while(turn == 2);//在此死循环,表示一直在看看Q进程什么时候结束访问临界区
pturn = true;
}
}
//访问临界区的代码
// ...
turn = 2;//P访问完了临界区,设置turn=2表示可以让Q访问了
pturn = false;
//Q进程
qturn = true;
while(pturn){
if(turn == 1){//如果发现了互相谦让,且turn==1表示在这种情况下P进程先访问临界区
qturn = false;//表示先放弃自己想访问临界区的意愿
while(turn == 1);//在此死循环,表示一直在看看P进程什么时候结束访问临界区
qturn = true;
}
}
//访问临界区的代码
// ...
turn = 1;//Q访问完了临界区,设置turn=1表示可以让P访问了
qturn = false;
我们来看DEKKER算法是怎么解决这个问题的:
首先假设P进程先进行。P进程在pturn= true即表示P进程想访问临界区之后被切出了CPU,然后Q进程上CPU。Q进程吧qturn置为true,表示自己也想进临界区,然后进入循环。因为此时pturn==true表示Q知道了P也想进临界区,所以它在循环中加上了判断:当turn==1的时候,优先认为P先访问临界区。那么他把自己的qturn置为false,表示自己先不进了,然后陷入循环,这个循环就是时刻来看P进程什么时候结束对临界区访问的(因为我们看到P进程访问临界区结束之后会把自己的turn 置为2方便Q进入)。Q陷入死循环之后随着时间片的结束被切出CPU,P进程上。P发现turn==1,且qturn = false所以直接结束循环访问了临界区,然后结束访问之后把turn置为2,自己的pturn = false;之后Q进程上了CPU,发现turn==2说明P进程已经结束访问了,所以也从死循环里面跳出来,接着访问临界区资源了。
所以从此来看,一个turn就能解决当同时想访问但是互相谦让的情况下,谁先访问的问题。比如turn==1说明P先访问,所以Q会一直陷入死循环,并且把qturn=false彻底让出临界区,让P进程先访问,这就是dekker算法的精髓。