死锁是进程并发执行过程中可能出现的现象,哲学家就餐问题是描述死锁的经典例子。为了防止死锁,可以采用资源预分配法或者资源按序分配法。资源预分配法是指进程在运行前一次性地向系统申请它所需要的全部资源,如果系统当前不能够满足进程的全部资源请求,则不分配资源, 此进程暂不投入运行,如果系统当前能够满足进程的全部资源请求, 则一次性地将所申请的资源全部分配给申请进程。资源按序分配法是指事先将所有资源类全排序, 即赋予每一个资源类一个唯一的整数,规定进程必需按照资源编号由小到大的次序申请资源。
设计内容:模拟有五个哲学家的哲学家进餐问题。
问题描述:哲学家的生活就是思考和吃饭,即思考,饿了就餐,再思考,循环往复。要求是:每一个哲学家只有在拿到位于他左右的筷子后,才能够就餐;哲学家只能先拿左边的筷子,再去拿右边的筷子,而不能同时去抓他两边的筷子,也不能从其他哲学家手中抢夺筷子;哲学家每次就餐后必须放下他手中的两把筷子后恢复思考,不能强抓住餐具不放。
以下给出了三种解决死锁问题的方法,请仔细阅读,选择一种实现。
原理A:至多只允许四个哲学家同时进餐,以保证至少有一个哲学家能够进餐,最终总会释放出他所使用过的两支筷子,从而可使更多的哲学家进餐。将room作为信号量,只允许4个哲学家同时进入餐厅就餐,这样就能保证至少有一个哲学家可以就餐,而申请进入餐厅的哲学家进入room的等待队列。根据FIFO的原则,总会进入就餐。因此不会出现饿死和死锁的现象。
伪码
Semaphorechopstick[5]={1,1,1,1,1};
Semaphoreroom=4;
Voidphilosopher(int i)
{
while(true)
{
Think();
Wait(room);//请求进入房间进餐
wait(chopstick[i]);//请求左手边的筷子
wait(chopstick[(i+1)]%5);//请求右手边的筷子
eat();
signal(chopstick[(i+1)]%5);//释放右手边的筷子
singal(chopstick[i]);//释放右手边的筷子
singal(room);
}
}
原理B:仅当哲学家的左右筷子都可用时,才允许他拿起筷子进餐。
方法1:利用AND型信号量机制实现:在一个原语中,将一段代码同时需要的多个临界资源,要么全部分配给它,要么一个都不分配,因此不会出现死锁的情形。当某些资源不够时阻塞调用进程;由于等待队列的存在,使得对资源的请求满足FIFO的要求,因此不会出现饥饿的情形。
伪码:
Semaphorechopstick[5]={1,1,1,1,1};
Voidphilosopher(int I)
{while(true)
{
Think();
Swait(chopstick[(I+1)]%5,chopstick[I]);
eat();
Ssignal(chopstick[(I+1)]%5,chopstick[I]);
}
}
方法2:利用信号的保护机制实现,通过信号量mutex对eat()之前的取左侧和右侧筷子的操作进行保护,使之成为一个原子操作这样可以防止死锁的出现。
伪码:
Semaphore=1;
Semaphorechopstick[5]={1,1,1,1,1};
voidphilosopher(int I)
{while(true)
{
think();
wait(mutex);
wait(chopstick[(I+1)]%5);
wait(chopstick[I]);
signal(mutex);
eat();
signal(chopstick[(I+1)]%5);
singal(chopstick[I]);
}
}
原理C:规定奇数号的哲学家先拿起他左边的筷子,然后再去拿他右边的筷子;而偶数号的哲学家则相反。按此规定,将是1,2号哲学家竞争1号筷子,3,4号哲学家竞争3号筷子。即五个哲学家都竞争奇数号筷子,获得后,再去竞争偶数号筷子,最后总会有一个哲学家能获得两支筷子而进餐。而申请不到的哲学家进入阻塞等待队列,跟FIFO原则,则先申请的哲学家会较先可以吃饭,因此不会出现饿死的哲学家。
伪码:
Semaphorechopstick[5]={1,1,1,1,1};
voidphilosopher(int i)
{
While(true)
{
Think();
If(i%2==0)//偶数号哲学家,先右后左
{
Wait(chopstick[i+1]%5);
Wait(chopsticl[i]);
eat();
signal(chopstick[(i+1)]%5);
singal(chopstick[i]);
}
else
{
Wait(chopsticl[i]);
Wait(chopstick[i+1]%5);
eat();
singal(chopstick[i]);
signal(chopstick[(i+1)]%5);
}
}