哲学家问题

Dijkstra提出并解决的哲学家就餐问题是经典的进程同步问题。哲学家就餐问题描述如下:

有5个哲学家共用一张圆桌,分别坐在周围的5张椅子上,在圆桌上有5个碗和5只筷子,他们的生活方式是交替地进行思考和进餐。平时,每个哲学家进行思考,饥饿时便试图拿起其左右最靠近他的筷子,只有在他拿到两只筷子时才能进餐。进餐完毕,放下筷子继续思考。

桌子上的筷子f0,f1,…,f4是临界资源,应互斥使用,可用一个信号量表示一只筷子,5只筷子的5个信号量构成信号量数组,所有信号量的初值均为1。

struct semaphore chopstick[5] ;
chopstick[0].value=chopstick[1].value=1;
chopstick[2].value=chopstick[3].value=1 ;
chopstick[4].value=1 ;


每个哲学家算法流程:

(1) 拿起左、右筷子;
(2) 吃面条;
(3) 放下左、右筷子;
(4) 思考问题;
(5) 返回(1)。

 

则第i个哲学家的活动可描述如下:

cobegin
process  Pi(i = 0,1,2,3,4)
{
    while (TRUE)
    {  wait(chopstick[i]);                     //拿起左边筷子
        wait(chopstick[(i + 1)%5]); //拿起右边筷子 
        eating ;
        signal(chopstick[i]);                  //放下左边筷子
        signal(chopstick[(i+1)%5]);//放下右边筷子
        thinking ;
    }
}
coend 

该方法虽然保证了临界资源的互斥使用,但是可能导致死锁。5个哲学家可能每个人都拿起自己的左筷子,但是却无法拿到自己的右筷子。既无法释放自己的筷子,也等不到别人的筷子完成自己的活动,最终形成死锁。

 

对于上述的死锁,可以采用以下的方法解决:

(1)至多允许4个哲学家同时取左边的筷子,这样能至少保证一个哲学家能就餐,并在用毕后释放他用过的两只筷子,从而使更多的哲学家能够进餐。
(2)仅当哲学家左右两只筷子均可用时,才允许他拿起筷子进餐。(用AND信号量机制)
(3)规定奇数号哲学家先拿左边筷子,然后再拿右边筷子;而偶数号哲学家先拿右边筷子,然后再拿左边筷子。

 

  1. 至多允许4个哲学家同时取左边的筷子算法

         至多只允许四个哲学家同时进餐,以保证至少有一个哲学家能够进餐, 最终总会释放出他所使用过的两支筷子,从而可使更多的哲学家进餐。以下将room 作为信号量,只允许4 个哲学家同时进入餐厅就餐,这样就能保证至少有一个哲学家可以就餐,而申请进入餐厅的哲学家进入room 的等待队列,根据FIFO 的原则,总会进入到餐厅就餐,因此不会出现饿死和死锁的现象。

semaphore chopstick[5]={1,1,1,1,1};
semaphore room=4;
void philosopher(int i){
    while(true){
                think();  
                wait(room); //请求进入房间进餐  
                wait(chopstick[i]); //请求左手边的筷子  
                wait(chopstick[(i+1)%5]); //请求右手边的筷子  
                eat();  
                signal(chopstick[(i+1)%5]); //释放右手边的筷子  
                signal(chopstick[i]); //释放左手边的筷子  
                signal(room); //退出房间释放信号量room 
                } 
    }

     2.当左右筷子均可用时(AND信号量)

        仅当哲学家的左右两支筷子都可用时,才允许他拿起筷子进餐。 利用AND 型信号量机制实现:在一个原语中,将一段代码同时需要的多个临界资源,要么全部分配给它,要么一个都不分配,因此不会出现死锁的情形。当某些资源不够时阻塞调用进程;由于等待队列的存在,使得对资源的请求满足FIFO 的要求,因此不会出现饥饿的情形。

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

除了使用AND信号量,只用记录型信号量也可以。但是需要额外设置一个信号量。

仅当哲学家的左右两支筷子都可用时,才允许他拿起筷子进餐。 利用信号量的保护机制实现:通过信号量mutex对eat()之前的取左侧和右侧筷子的操作进行保护,使之成为一个原子操作,这样可以防止死锁的出现。

Mutex实际上是让每次都只有一个哲学家去拿左右筷子

当抢到左右筷子的这个哲学家吃饭时候,mutex就可以放其它的哲学家中的一个进来抢(or等待)他的左右筷子了)。

 

   3.奇数号和偶数号方法

        规定奇数号的哲学家先拿起他左边的筷子,然后再去拿他右边的筷子;而偶数号的哲学家则相反.按此规定,将是1,2号哲学家竞争1号筷子,3,4号哲学家竞争3号筷子.即五个哲学家都竞争奇数号筷子,获得后,再去竞争偶数号筷子。最后总会有一个哲学家能获得两支筷子而进餐。而申请不到的哲学家进入阻塞等待队列,根FIFO原则,则先申请的哲学家会较先可以吃饭,因此不会出现饿死的哲学家。

 

 

 

 

  • 6
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值