问题描述:有五个哲学家围坐在一张圆桌旁就餐,,圆桌上有五个碗和五只筷子,他们的生活方式就是交替地进行思考和进餐。平时每个哲学家独立思考问题,饥饿时便试图分别取其左右两侧的筷子,只有两只筷子都拿到后才能进餐;进餐完毕后应立即放下筷子,然后继续思考问题。
问题分析:由问题描述可知,哲学家共享的五只筷子是临界资源,为实现筷子的互斥使用,可为每只筷子设置一个互斥信号量,初值为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); 
}