操作系统——哲学家进餐问题的解决方法
一、问题描述
五个哲学家共用一张圆桌,分别坐在五张椅子上,圆桌上有五个碗和五只筷子。平时哲学家进行思考,当即饥饿时拿起左右两边的筷子,只有拿到两只筷子时才能进餐,进餐完毕,放下筷子继续思考。
二、问题分析
这是经典的进程同步问题。筷子是临界资源,每只筷子都用一个互斥量表示。
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);
}