- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
哲学家进餐问题 05611 贺美琛 冯文中 问题描述 设有五个哲学家,共用一张放有五把椅子的餐桌,每人坐在一把椅子上,桌子上有五个碗和五只叉子,每人两边各放一只叉子。哲学家们是交替思考和进餐,饥饿时便试图取其左右最靠近他的叉子。 算法 A void philosopher(int i) /*i:哲学家编号,从0 到4*/ { while (TRUE) { think( ); /*哲学家正在思考*/ take_fork(i); /*取左侧的叉子*/ take_fork((i+1) % N); /*取右侧叉子;%为取模运算*/ eat( ); /*吃饭*/ put_fork(i); /*把左侧叉子放回桌子*/ put_fork((i+1) % N); /*把右侧叉子放回桌子*/ } } 算法分析: 当出现以下情形,在某一个瞬间,所有的哲学家都同时启动这个算法,拿起左侧的叉子,而看到右侧叉子不可用,又都放下左侧叉子,等一会儿,又同时拿起左侧叉子……如此这样永远重复下去。对于这种情况,所有的哲学家都吃不上饭。 算法改善: 改进后的算法A 算法 B 思想 规定奇数号的哲学家先拿起他左边的叉子,然后再去拿他右边的叉子;而偶数号的哲学家则相反.按此规定,将是1,2号哲学家竞争1号叉子,3,4号哲学家竞争3号叉子.即五个哲学家都竞争奇数号叉子,获得后,再去竞争偶数号叉子,最后总会有一个哲学家能获得两支叉子而进餐。而申请不到的哲学家进入阻塞等待队列,根据FIFO原则,则先申请的哲学家会较先可以吃饭,因此不会出现饿死的哲学家。 算法 C思想: 仅当哲学家的左右两支叉子都可用时,才允许他拿起叉子进餐。 方法1 在一个原语中,将一段代码同时需要的多个临界资源,要么全部分配给它,要么一个都不分配,因此不会出现死锁的情形。当某些资源不够时阻塞调用进程;由于等待队列的存在,使得对资源的请求满足FIFO 的要求,因此不会出现饥饿的情形。 方法2 通过信号量mutex对eat()之前的取左侧和右侧叉子的操作进行保护,使之成为一个原子操作,这样可以防止死锁的出现。 算法 D思想: 原理:不是对每只叉子设置信号量,而是对每个哲学家设置信号量。 Test()函数的作用声明: a. 如果当前处理的哲学家处于饥饿状态且两侧哲学家不在吃饭状态,则当前哲学家通过test()函数试图进入吃饭状态。 b. 如果通过test()进入吃饭状态不成功,那么当前哲学家就在该信号量阻塞等待,直到其他的哲学家进程通过test()将该哲学家的状态设置为EATING。 c. 当一个哲学家进程调用put_forks()放下叉子的时候,会通过test()测试它的邻居,如果邻居处于饥饿状态,且该邻居的邻居不在吃饭状态,则该邻居进入吃饭状态。 以下为代码: #define N 5 /* 哲学家人数*/ #define LEFT (i-1+N)%N /* i的左邻号码 */ #define RIGHT (i+1)%N /* i的右邻号码 */ typedef enum { THINKING, HUNGRY, EATING } phil_state; /*哲学家状态*/ monitor dp /*管程*/ { phil_state state[N]; semaphore mutex =1; semaphore s[N]; /*每个哲学家一个信号量,初始值为0*/ * * (1) 只有拿到两只叉子时,哲学家才能吃饭。(2) 如果叉子已被别人拿走,则必须等别人吃完之后才能拿到叉子。 怎样才能保证哲学家不被饿死呢? 摘 要:解决“哲学家进餐”问题首先要找出对应的控制关系,设定相应的控制信号量。避免死锁也是解决该类问题的关键。 关键词:进程同步;信号量;临界资源;临界区; 死锁 至多只允许四个哲
文档评论(0)