
王道操作系统笔记视频链接2.3.5.3 哲学家进餐问题问题描述问题描述一张圆桌上坐着5名哲学家每两个哲学家之间的桌上摆一根筷子桌子的中间是一碗米饭。哲学家们倾注毕生的精力用于思考和进餐哲学家在思考时并不影响他人。只有当哲学家饥饿时才试图拿起左、右两根筷子一根一根地拿起。如果筷子已在他人的手上则需等待。饥饿的哲学家只有同时拿起两根筷子才可以开始进餐当进餐完毕后放下筷子继续思考。如图思考流程关系分析系统中有5个哲学家进程5位哲学家与左右邻居对其间筷子的访问是互斥关系。整理思路这个问题中只有互斥关系但与之前遇到的问题不同的是每个哲学家进程需要同时持有两个临界资源才能开始吃饭。如何避免临界资源分配不当造成的死锁现象是哲学家问题的精髓。信号量设置定义互斥信号量数组 chopstick[5]{1,1,1,1,1} 用于实现对5个筷子的互斥访问。并对哲学家按0~4编号哲学家 i 左边的筷子编号为 i右边的筷子编号为 (i1)%5。如图如何防止死锁的发生①可以对哲学家进程施加一些限制条件比如最多允许四个哲学家同时进餐。这样可以保证至少有一个哲学家是可以拿到左右两只筷子的。②要求奇数号哲学家先拿左边的筷子然后再拿右边的筷子而偶数号哲学家刚好相反。用这种方法可以保证如果相邻的两个奇偶号哲学家都想吃饭那么只会有其中一个可以拿起第一只筷子另一个会直接阻塞。这就避免了占有一支后再等待另一只的情况。③仅当一个哲学家左右两支筷子都可用时才允许他抓起筷子。尝试解题个人解题步骤// 第一个方法semaphore count4;//最多四个人同时吃饭semaphore chopstick[5]{1,1,1,1,1}philosopher_k(){intik;while(1){准备吃饭;P(count);//占个位置P(chopstick[i]);//拿左边筷子P(chopstick[(i1)%5]);//拿右边筷子开始吃饭;V(count);//释放位置V(chopstick[i]);//释放左边筷子V(chopstick[(i1)%5]);//释放右边筷子}}// 第二个方法semaphore chopstick[5]{1,1,1,1,1}philosopher_k(){intik;boolis_odd(i%21);//判断是否为奇数while(1){准备吃饭;if(is_odd){//奇数先拿左再拿右P(chopstick[i]);//拿左边筷子P(chopstick[(i1)%5]);//拿右边筷子}else{//偶数先拿右再拿左P(chopstick[(i1)%5]);//拿右边筷子P(chopstick[i]);//拿左边筷子}开始吃饭;V(chopstick[i]);//释放左边筷子V(chopstick[(i1)%5]);//释放右边筷子}}视频的第三种方法的代码semaphore chopstick[5]{1,1,1,1,1};semaphore mutex1;//互斥地取筷子Pi(){//i号哲学家的进程while(1){P(mutex);P(chopstick[i]);//拿左P(chopstick[(i1)%5]);//拿右V(mutex);吃饭...V(chopstick[i]);//放左V(chopstick[(i1)%5]);//放右思考...}}// 严格来说这种方法并不能保证至于两边的筷子都可用时才允许哲学家拿起筷子// 比如0号哲学家拿了0和1号筷子如果转换到4号哲学家进程// 那么4号哲学家会拿起4号筷子并且阻塞等待0号筷子// 此时就并不是两边筷子都可用但是仍然拿了筷子。// 更准确的说法应该是// 各哲学家拿筷子这件事必须互斥的执行。// 这就保证了即使一个哲学家在拿筷子拿到一半时被阻塞也不会有别的哲学家会继续尝试拿筷子。// 这样的话当前正在吃饭的哲学家放下筷子后被阻塞的哲学家就可以获得等待的筷子了。知识回顾与重要考点哲学家进餐问题的关键在于解决进程死锁。这些进程之间只存在互斥关系但是与之前接触到的互斥关系不同的是每个进程都需要同时持有两个临界资源因此就有了“死锁”问题的隐患。如果在考试中遇到了一个进程需要同时持有多个临界资源的情况应该参考哲学家问题的思想分析题中给出的进程之间是否会发生循环等待是否会发生死锁。可以参考哲学家就餐问题解决死锁的三种思路。关于死锁的更详细内容会在后续小节补充