哲学家就餐问题
问题描述:
一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上摆一根筷子,桌子的中间是一碗米饭。哲学家们倾注毕生的精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时,
才试图拿起左、右两根筷子(一根一根地拿起)。如果筷子已在他人手上,则需等待。饥饿的哲
学家只有同时拿起两根筷子才可以开始进餐,当进餐完毕后,放下筷子继续思考。
问题分析:
每个哲学家之间拿筷子都是互斥的,如果五个哲学家同时拿筷子则会出现一人一个筷子,则每个哲学家都陷入等待状态而造成死锁。
为了避免死锁现象,可以采取以下三种措施:
- 最多允许4个哲学家同时去拿左边的筷子;
- 仅当一个哲学家左右两边的筷子都可用时,才允许他拿筷子;
- 给所有哲学家编号,奇数号的哲学家必须首先拿左边的筷子,偶数号的哲学家则反之
第一种措施:允许4个哲学家只拿一边的筷子,那么最后一定空余一根筷子,此时离那根筷子近的哲学家就可以拿起剩余的一根筷子吃饭,吃完后释放筷子资源,以便剩余四个哲学家就餐。
第二种措施:五个哲学家随机拿筷子,当五个哲学家中有同时拿到两根筷子的就进行就餐,反之如果都只拿到一根筷子时则全部释放掉筷子重新选取。
第三种措施:这样可以保证一号和二号同时竞争1号筷子,三号和四号同时竞争3号筷子,五号竞争5号筷子。即五位哲学家都先竞争1、3、5奇数号筷子,然后再去竞争剩下的偶数号筷子,这样可以确保一定有哲学家可以拿到两根筷子。
设置互斥信号量数组chopsticka[5]={1,1,1,1,1}表示五根筷子之间互斥访问。
伪代码:
//第一种措施:只允许四个哲学家拿筷子
semaphore chopsticks[5]={1,1,1,1,1};//五根筷子之间拿取互斥
semaphore count=4;//只允许四个哲学家拿筷子
process(){
while(1){
思考怎么拿筷子;
p(count); //进入只允许四个互斥的设定
p(chopsticks[i]); //拿左边的筷子
p(chopsticks[(i+1)%5]);//拿右边的筷子
拿完筷子就餐;
v(chopsticks[i]); //释放左边的筷子
v(chopsticks[(i+1)%5]); //释放右边的筷子
v(count); //离开只允许四个互斥的设定
}
}
//第二种措施:必须同时拿到两个筷子才可以进餐
semaphore chopsticks[5]={1,1,1,1,1};//五根筷子之间拿取互斥
semaphore mutex=1;//只允许一个哲学家同时拿两双筷子
process(){
while(1){
思考怎么拿筷子;
p(mutex); //进入只允许一个哲学家同时拿两双筷子的设定
p(chopsticks[i]); //拿左边的筷子
p(chopsticks[(i+1)%5]);//拿右边的筷子
v(mutex) //拿完释放该设定,允许其他哲学家进入该设定继续拿筷子
拿完筷子就餐;
v(chopsticks[i]); //释放左边的筷子
v(chopsticks[(i+1)%5]); //释放右边的筷子
}
}
//第三种措施:奇数号的哲学家必须首先拿左边的筷子,偶数号的哲学家则反之
semaphore chopsticks[5]={1,1,1,1,1};//五根筷子之间拿取互斥
process(){
while(1){
思考怎么拿筷子;
if(i%2==1) { //进入只允许一个哲学家同时拿两双筷子的设定
p(chopsticks[i]); //先拿左边的筷子
p(chopsticks[(i+1)%5]);//后拿右边的筷子
}
else {
p(chopsticks[(i+1)%5]);//先拿右边的筷子
p(chopsticks[i]); //后拿左边的筷子
}
拿完筷子就餐;
v(chopsticks[i]); //释放左边的筷子
v(chopsticks[(i+1)%5]); //释放右边的筷子
}
}
其他进程同步问题以及一些真题练习请看我的其他博客~~