问题描述:有五个哲学家围坐在一张圆桌旁就餐,,圆桌上有五个碗和五只筷子,他们的生活方式就是交替地进行思考和进餐。平时每个哲学家独立思考问题,饥饿时便试图分别取其左右两侧的筷子,只有两只筷子都拿到后才能进餐;进餐完毕后应立即放下筷子,然后继续思考问题。
问题分析:由问题描述可知,哲学家共享的五只筷子是临界资源,为实现筷子的互斥使用,可为每只筷子设置一个互斥信号量,初值为1,使用一个信号量数组来表示。为描述方便,对每个哲学家进行编号:0~4;五只筷子及其对应的信号量编号也是0~4,且与哲学家编号相同的筷子位于该哲学家左侧。一种简单的解决思路是每个哲学家都先取其左侧的筷子,成功后再取其右侧的筷子,取到两只筷子后就进餐;进餐完毕后再一次释放着两只筷子。该思路描述如下:
semaphore chop[5];
void main(){
chop[5]={1,1,1,1,1};
parbegin(Philosopher(i)(i=0...4));
}
void Philosopher(i){
do{
thinking;
wait(chop[i]);
wait(chop[i+1]mod5);
eating;
signal(chop[i]);
signal)chop[i+1]mod5);
}while(1);
}
分析:如果五个哲学家同时成功取到左边的筷子,之后再取右边的筷子时都会失败。五个哲学家都等待右侧筷子而不能吃饭,且都不能释放已取到的左边的筷子,进入死锁状态。
下面提出一些可以避免死锁的算法
(1)原理:最多允许四个哲学家同时去取左侧的筷子,这样至少能保证一个哲学家成功拿到两只筷子。
semaphore chop[5];
semaphore take;
void main(){
chop[5]={1,1,1,1,1};
take=4;
parbegin(Philosopher(i)(i=0...4));
}
void Philosopher(i)
{
do{
thinking;
wait(take); //请求拿筷子
wait(chopstick[i]); //请求左手边的筷子
wait(chopstick[(i+1)mod5]); //请求右手边的筷子
eating;
signal(chopstick[(i+1)mod5]); //释放右手边的筷子
signal(chopstick[i]); //释放左手边的筷子
signal(take);
}while(1);
}
(2)原理:仅当哲学家左右两侧的筷子都可用时,才允许他一次性同时拿起两只筷子。
semaphore chop[5];
void main(){
chop[5]={1,1,1,1,1};
parbegin(Philosopher(i)(i=0...4));
}
void Philosopher(i)
{
do {
thinking;
Swait(chopstick[(i+1)]mod5,chop[i]);
eating;
Ssignal(chopstick[(i+1)]mod5,chop[i]);
}while(1);
}
(3)原理:规定奇数编号哲学家先取其左侧筷子,成功后再取其右侧筷子;而偶数编号哲学家则相反,先取其右侧筷子,成功后再取其左侧筷子。这样可以保证一个哲学家能取到两只筷子。
semaphore chop[5];
void main(){
chop[5]={1,1,1,1,1};
parbegin(Philosopher(i)(i=0...4));
}
void Philosopher(i)
{
do{
thinking;
if(imod2 == 0) //偶数哲学家,先右后左。
{
wait(chop[i+1]mod5) ;
wait(chop[i]) ;
eating;
signal(chop[i+1]mod5) ;
signal(chop[i]) ;
}
else //奇数哲学家,先左后右。
{
wait(chop[i]) ;
wait(chop[i+1]mod 5) ;
eating;
signal(chop[i]) ;
signal(chop[i+1]mod 5) ;
}
}while(1);
}
参考https://blog.youkuaiyun.com/liujianfei526/article/details/51891534