操作系统——哲学家进餐问题的解决方法

一、问题描述

五个哲学家共用一张圆桌,分别坐在五张椅子上,圆桌上有五个碗和五只筷子。平时哲学家进行思考,当即饥饿时拿起左右两边的筷子,只有拿到两只筷子时才能进餐,进餐完毕,放下筷子继续思考。

二、问题分析

这是经典的进程同步问题。筷子是临界资源,每只筷子都用一个互斥量表示。
semaphore chopstick[5] = {1, 1, 1, 1, 1}
错误示例:

semaphore chopstick[5] = {1, 1, 1, 1, 1};
void philosopher(int i){
    do{
        wait(chopstick[i]);
        wait(chopstick[(i+1)%5]);
        //eat
        //...
        signal(chopstick[i]);
        signal(chopstick[(i+1)%5]);
        
        //think
        //...
    }while(true);
}

这样做会带来一个问题,当五个哲学家同时饥饿拿起左边的筷子时,试图拿右边的筷子,就会进入死锁。

三、解决方法

1.至多有四位哲学家同时拿起左边的筷子,即至多只有四个哲学家同时进餐,这样能保证至少有一个哲学家能够进餐。
2.仅当哲学家左右两边的筷子都可用时,才能进餐
3.规定奇数号哲学家先拿左边的筷子,再拿右边的筷子;偶数号哲学家相反。

解法1

用一个信号量counter表示哲学家同时进餐的人数,初始值为4

semaphore chopstick[5] = {1, 1, 1, 1, 1};
counter=4;
void philosopher(int i){
    do{
        wait(counter);
        wait(chopstick[i]);
        wait(chopstick[(i+1)%5]);
        //eat
        //...
        signal(chopstick[i]);
        signal(chopstick[(i+1)%5]);
        signal(counter)
        //think
        //...
    }while(true);
}

解法2

使用AND型信号量,当两个临界资源都满足后才能进餐

semaphore chopstick[5] = {1, 1, 1, 1, 1};
void philosopher(int i){
    do{
        Swait(chopstick[i], chopstick[(i+1)%5]);
        //eat
        //...
        Ssignal(chopstick[i], chopstick[(i+1)%5]);
        //think
        //...
    }while(true);
}

解法3

semaphore chopstick[5] = {1, 1, 1, 1, 1};
void philosopher(int i){
    do{
        if(i%2){
            wait(chopstick[i]);
            wait(chopstick[(i+1)%5]);
        }
        else{
            wait(chopstick[(i+1)%5]);
            wait(chopstick[i]);
        }
        //eat
        //...
        signal(chopstick[i]);
        signal(chopstick[(i+1)%5]);
        //think
        //...
    }while(true);
}
posted @ 2021-10-11 23:08  inss!w!  阅读(777)  评论(0编辑  收藏  举报