本文章参考b站视频BV1Xk41q7RK
1.问题描述
有五个哲学家围在一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,他们的生活方式是交替的进行思考和进餐。平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的筷子,只有在他拿到两支筷子时才能进餐。进餐完毕后,放下筷子继续思考。
2.问题分析
1.记录型信号量
先操作,后判断
wait(Semaphare S){
S.value--;
if(S.value < 0){
black(S.L); // 阻塞状态
}
}
signal(Semaphare S){
S.value++; //释放资源量
if(S.value <= 0){
wakeup(S.L); //唤醒一个进程
}
}
2.利用记录性信号解决哲学家进餐问题
1.筷子是临界资源,在一段时间内只允许一位哲学家使用。
2.一位哲学家需要拿两支筷子,左和右,即进入两个临界区,才可以吃饭
3.为了实现对筷子的互斥使用,可以用一个信号量表示一只筷子,有五个信号量构成信号量数组:
semaphore chopstick[5] = {
1,1,1,1,1};
//各个信号量初始值为1
//第i位哲学家的活动可描述为
do{
wait(chopstick[i]); //判断哲学家左边的筷子是否可用
wait(chopstick[(i+1)%5]);//判断哲学家右边的筷子是否可用
......
//吃饭
signal(chopstick[i]); //退出临界区,允许别的进程操作缓冲池
signal(chopstick[(i+1)%5]);//缓冲池中非空的缓冲区数量加1,可以唤醒等待的消费者进程
......
//思考
}while(1);
问:会陷入死锁状态吗?
答:会。分析程序,一位哲学家拿到两个筷子开始进餐,看上去似乎没有什么问题,但如果考虑到并发问题,五位哲学家同时拿了他们左边的筷子,此刻五支筷子都被占用,当哲学家想要拿到右边的筷子时,因为临界资源不足,进入阻塞状态,所有的哲学家都在阻塞状态,且不会释放他们所拿的左边的筷子,会一直阻塞,陷入死锁,无法进餐并思考.
解决办法:
1.至多允许4位哲学家去拿左边的筷子,最终保证有一位能吃上饭,用毕后释放两支筷子
2.规定奇数号拿他左边的筷子,然后去拿右边的筷子,偶数相反。
例如:两个相邻的人争位于他们之间的筷子
3.只有哲学家身边同时有左筷子和右筷子时,才允许拿起筷子就餐
4.对筷子进行编号,哲学家先拿编号小的筷子
5.如果哲学家拿起左边的筷子后,申请右边的筷子得不到满足,则放下左边的筷子,隔一段时间后再申请左边的筷子
方案一
至多允许4位哲学家去拿左边的筷子,最终保证有一位能吃上饭,用毕后释放两支筷子
实现方法:设置一个控制信号量 count 控制并发的数目,初始值为4
哲学家活动描述为
semaphare chopstick[5] = {
1,1,1,1};
semaphare count = 4;
do{
wait(count);
wait(chopstick[i]);
wait(chopstick[(i+1)%5]);
......
//吃饭
signal(chopstick[i]);
signal(chopstick[(i+1)%5]);
signal(count);
......
//思考
}while(1);
方案二
规定奇数号拿他左边的筷子,然后去拿右边的筷子,偶数相反。
例如:两个相邻的人争位于他们之间的筷子
do{
if(i%2 == 1){
wait(chopstick[i]);
wait(chopstick[(i+1)%5]);
}
else{
wait(chopstick[(i+1)%5]);
wait(chopstick[i]);
}
......
//吃饭
signal(chopstick[(i+1)%5]);
signal(chopstick[i]);
.......
//思考
}while(1);
方案三–利用AND信号量机制解决问题
在哲学家进餐问题中,一位哲学家需要拿到两支筷子(两个临界资源)才能进餐。这在本质上就是前面所介绍的AND信号量机制问题,故用此可以获得最简单的解法
semaphare chopstick[5] = {
1,1,1,1,1};
do{
.....
//think
Swait(chopstick[(i+1)%5],chopstick[i]);
......
//eat
Signal(chopstick[(i+1)%5],chopstick[i]);
}while(1);