哲学家就餐问题
- 格式:ppt
- 大小:1.33 MB
- 文档页数:23
红河学院课程设计报告操作系统课程名称:6个哲学家进餐设计题目:院系:工学院专业:计算机科学与技术班级:11计科班曹永前设计者:学号:201101030466指导教师:韦相2013 年 5 月26 日1. 问题描述:一个房间内有6个哲学家,他们的生活就是思考和进食。
哲学家思考后,过一定的时间就会饥饿,饥饿之后就想吃饭,吃饭后再思考。
房间里有一张圆桌,桌子周围放有五把椅子,分别属于五位哲学家每两位哲学家之间有一把叉子,哲学家进食时必须同时使用左右两把叉子。
2. 问题分析1、写出哲学家进餐的算法描述。
用六只筷子解决需要用两双筷子来进餐的六个哲学家,由于每个哲学家都需要其周围的两只筷子,所以筷子是公用信号量,这久需要设置一个互斥信号量,来使六个哲学家互斥的进餐.具体做法将六个信号量设置为0-5,用pv 源于来控制信号量,并将六个哲学家分别编号为0-5.经过仔细分析我们会发现,有这样一个问题存在,就是当每个哲学家都申请到他周围的一只筷子时,由于他们每人都只有一只筷子无法进餐,没有进餐他们就无法释放他们已经得得到的筷子,这样是进餐出于一种僵局,无法继续下去,这就是死锁问题.2、死锁问题的分析与具体的解决方法。
死锁问题就是当每个哲学家都拿到且只拿到一只筷子,这样每个哲学家都无法进餐,也无法释放所得到的筷子,所以解决死锁我们就要从这入手,就是怎样去预防使所有哲学家不要同时去申请他们同一方向的筷子.根据这解决死锁的方法有以下几种:a.每一次最多只能有五个哲学家申请进餐.这样其中的一个哲学家就能申请到两只筷子,就能够进餐,再将筷子释放给其他哲学家进餐.b.用AND信号量,就是哲学家需同时申请其左右两边的筷子,两边都有资源的时候,才能让这个哲学家得到资源,这样哲学家只要申请到筷子就能进餐, 再将筷子释放给其他哲学家进餐.c.用管程机制来实现。
d.我们前面已经将每个哲学家都分配了一个编号,我们可以编号为奇数的哲学家首先去申请其左边的筷子,再去申请其右手边的筷子;让编号为偶数的哲学家,先去申请其右边的筷子,再去申请其左边的筷子.我们可以看出编号为奇数的哲学家左边,与编号为偶数的哲学家的右边为同一只筷子,当其中一个哲学家拿到此筷子后,他另一边的筷子也是空闲的,这样就能避免死锁.主程序中我使用的是最后一种避免死锁的方法.3、用C程序实现哲学家进餐。
哲学家进餐问题的趣味例子
哲学家进餐问题是一个经典的计算机科学问题,用来展示并发编程中可能出现
的资源竞争和死锁问题。
这个问题的描述是:五位哲学家围坐在一张圆桌前,每位哲学家面前有一碗意面,但他们之间共享一把只能被一个人同时使用的餐叉。
每位哲学家需要先拿起右手边的餐叉,再拿起左手边的餐叉才能吃饭,吃完后放下餐叉继续思考问题。
如果哲学家之间同时试图拿起自己左右手边的餐叉,就会导致死锁问题,无法继续进餐。
这个问题的趣味例子在于通过这种抽象的场景,展现了并发编程中常见的竞争
和死锁问题。
实际上,哲学家进餐问题也可以被看作是对资源管理和同步机制的一种考验。
如果每位哲学家都按照固定的顺序拿餐叉,就不会发生死锁;而如果哲学家们都随机地尝试拿餐叉,就可能会出现资源竞争的问题,导致无法进餐。
这个问题的趣味之处在于,通过一个简单的场景,展示了复杂的并发编程中可
能出现的问题,让人们更加深入地理解并发编程中的挑战和技巧。
通过哲学家进餐问题的讨论,人们可以思考如何设计合理的同步机制和资源管理策略,避免竞争和死锁问题的发生,提高程序的并发性能和稳定性。
总的来说,哲学家进餐问题是一个充满趣味和启发的例子,能够帮助人们更好
地理解并发编程中的难点,同时也能够激发人们对于解决问题的创造力和思考能力。
通过这个例子的讨论,人们可以不仅仅学到技术知识,更能够培养出解决问题的能力和思维方式,为未来的学习和工作打下坚实的基础。
愿每位哲学家都能够顺利进餐,思考问题,探索未知的世界。
13、分析下面用信号量解决哲学家进餐问题的同步算法是否满足同步机制的准则。
若不满足,说明为什么,并给出满足同步机制准则的同步算法。
Var chopstick : array[0,...,4] of semaphore ;Chopstick[0]:=chopstick[1]:=chopstick[2]:=chopstick[3]:=chopstick[4]:=1;Pi: repeatwait(chopstick[i]);wait(chopstick[(i+1)mod 5]);eat ;signal(chopstick[i]);signal(chopstick[(i+1)mod 5]);think;until false;答:该算法不满足同步机制的"有限等待"原则,即每个哲学家都只拿一个筷子时就会产生死锁。
下面给出三种解决办法。
1、互斥申请资源设置信号量mutex初值为4,即最多可以有4个哲学家同时申请筷子。
这样保证了4个哲学家中至少有1人可以拿到两个筷子就餐而不发生死锁。
mutex=4Pi(i=0,1,...,4);Repeatwait(mutex);wait(chopstick[i]);wait(chopstick[(i+1) mod 5]);signal(mutex);Eat ;signal(chopstick[i]);signal(chopstick[(i+1)mod 5]);think;until false ;2、改变申请资源次序规定奇数号哲学家先拿起左边的筷子,然后再去拿右边的筷子;偶数号哲学家正好相反。
也即拿到一个筷子的哲学家才有权去拿下一个筷子,而没有拿到筷子的哲学家则退出竞争。
这样就不会出现5个哲学家都只拿一个筷子的情况。
pi(i=0,1,...4)repeatif odd(i) then /*如果i 为奇数*/beginwait(chopstick[i]);wait(chopstick[(i+1)mod 5]);endelsebeginwait(chopstick[(i+1)mod 5]);wait(chopstick[i]);endeat ;signal(chopstick[i]);signal(chopstick[(i+1)mod 5]);think;until false;3、采用AND型信号量机制AND型同步机制的思想是:将进程所需要的所有资源一次性全部分配给它,但只要有一个资源不能分配给该进程,则其它所有资源也不能分配给它。
{private:intnumber;intstatus;/*标记当前哲学家的状态,0表示正在等待(即处于饥饿状态),1表示得到两支筷子正在吃饭,2表示正在思考*/ public:Philosopher(intnum=0):status(2),number(num){}constintfind(){returnnumber;}constintgetinfo(){returnstatus;}voidChange();//状态改变函数voiddead_lock();};/////////voidPhilosopher::dead_lock(){EnterCriticalSection(&cs);//进入临界区strings;{}{}{}}{if(status==1)//正在进餐{tools[number%5]=true;//放下左手工具tools[(number-1)%5]=true;//放下右手工具status=2;//改变状态为思考}elseif(status==2)//思考中{status=0;//改变状态为等待}elseif(status==0)//等待中{if(tools[number%5]&&tools[(number-1)%5])//左右手两边工具均为空闲状态{tools[number%5]=false;//拿起左手工具tools[(number-1)%5]=false;//拿起右手工具status=1;}}LeaveCriticalSection(&cs);}{}{}{for(inti=0;i<5;i++)tools[i]=true;//筷子都未使用,初始化PhilosopherP1(1),P2(2),P3(3),P4(4),P5(5);InitializeCriticalSection(&cs);//初始化初始化临界区cout<<"-----------------------状态说明示意图:-----------------------"<<endl; cout<<""<<"哲学家1号的状态"<<""<<endl;cout<<"筷子0的状态"<<""<<"筷子1的状态"<<endl;cout<<"哲学家5号的状态"<<""<<"哲学家2号的状态"<<endl;cout<<"筷子4的状态"<<""<<"筷子2的状态"<<endl;cout<<"哲学家4号的状态"<<""<<"哲学家3号的状态"<<endl;cout<<""<<"筷子3的状态"<<endl;//cout<<""<<"哲学家3号的状态"<<""<<endl;cout<<"筷子的状态,用表示使用中,闲表示空闲中。
五个哲学家吃饭问题详细解答在一个阳光明媚的下午,五个哲学家聚在一起,准备享用一顿丰盛的午餐。
听起来很简单吧?但实际上,这顿饭可没那么容易!让我们来看看这群头脑发达的哲学家是如何在吃饭问题上纠结的。
1. 场景设定1.1 哲学家的基本设定这五位哲学家,一个比一个聪明。
他们分别是苏格拉底、柏拉图、康德、尼采和海德格尔。
你可以想象,他们脑袋里装的全是复杂的哲学思想,而不是食物的搭配。
所以,当这五位坐下来,面对一桌子美味的食物时,事情就开始变得有趣了。
1.2 吃饭的挑战问题来了:他们每个人都必须遵守一个规则——不可以同时吃饭,得轮流。
你想想,五个哲学家加上一个轮流吃饭的规则,这可真是“见鬼了”的挑战!想要吃上一口美味的菜,简直比推理一个哲学命题还难。
他们轮流吃饭的原则,真是把这顿饭变成了一场智力的较量。
2. 各自的哲学观2.1 苏格拉底的理性苏格拉底首先站出来,他一边抚摸着自己的胡须,一边说:“吃饭嘛,首先得用理性来解决问题。
”他鼓励大家先讨论,谁应该先吃,谁应该后吃。
他认为,只有通过理性对话,才能达到最佳的吃饭方案。
可是,你能想象吗?这一讨论持续了整整一个小时,食物都快冷掉了!2.2 柏拉图的理想接着柏拉图出场,他满脸严肃地说:“我们要追求理想的吃饭方式。
”他想出了一个绝妙的主意:每个人都应该依照自己的德性来决定吃的顺序。
结果,大家一顿争论,谁的德性更高?苏格拉底说他是智者,康德坚持说自己是道德之父,而尼采则跳出来,吼着“超人才能吃超好的饭!”搞得大家乱成一团,吃的机会又飞了。
3. 饥饿的对抗3.1 食物的诱惑这时,桌子上的食物开始散发出诱人的香气,真是令人垂涎欲滴。
五位哲学家每个人的肚子都开始抗议,仿佛在唱着“我们要吃饭”的歌。
吃饭这件事,从理性讨论变成了一场生存竞争。
每个人都在默默地想着:“快点!要是再不吃,我的哲学思想就要被饿死了!”3.2 轮流的尴尬最终,他们决定采取轮流吃饭的方式。
可当轮到康德的时候,他又开始喋喋不休,讲起了“绝对命令”的哲学,让其他人都想打瞌睡。
哲学家进餐问题1.问题描述:哲学家进餐问题描述有五个哲学家,他们的生活方式是交替地进行思考和进餐,哲学家们共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,平时哲学家进行思考,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,该哲学家进餐完毕后,放下左右两只筷子又继续思考。
约束条件(1)只有拿到两只筷子时,哲学家才能吃饭。
(2)如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子。
(3)任一哲学家在自己未拿到两只筷子吃完饭前,不会放下手中已经拿到的筷子。
2.求解方法(1).信号量的设置放在桌子上的筷子是临界资源,在一段时间内只允许一位哲学家使用,为了实现对筷子的互斥访问,可以用一个信号量表示筷子,由这五个信号量构成信号量数组。
semaphore chopstick[5] = {1,1,1,1,1};while(true){/*当哲学家饥饿时,总是先拿左边的筷子,再拿右边的筷子*/wait(chopstick[i]);wait(chopstick[(i+1)%5]);// 吃饭/*当哲学家进餐完成后,总是先放下左边的筷子,再放下右边的筷子*/signal(chopstick[i]);signal(chopstick[(i+1)%5]);}上述的代码可以保证不会有两个相邻的哲学家同时进餐,但却可能引起死锁的情况。
假如五位哲学家同时饥饿而都拿起的左边的筷子,就会使五个信号量chopstick都为0,当他们试图去拿右手边的筷子时,都将无筷子而陷入无限期的等待。
(2)避免死锁策略一原理:至多只允许四个哲学家同时进餐,以保证至少有一个哲学家能够进餐,最终总会释放出他所使用过的两支筷子,从而可使更多的哲学家进餐。
定义信号量count,只允许4个哲学家同时进餐,这样就能保证至少有一个哲学家可以就餐。
semaphore chopstick[5]={1,1,1,1,1};semaphore count=4; // 设置一个count,最多有四个哲学家可以进来void philosopher(int i){while(true){think();wait(count); //请求进入房间进餐 当count为0时 不能允许哲学家再进来了wait(chopstick[i]); //请求左手边的筷子wait(chopstick[(i+1)%5]); //请求右手边的筷子eat();signal(chopstick[i]); //释放左手边的筷子signal(chopstick[(i+1)%5]); //释放右手边的筷子signal(count); //退出房间释放信号量}}策略二原理:仅当哲学家的左右两支筷子都可用时,才允许他拿起筷子进餐。
哲学家就餐问题运行环境:linux 2.6.38-8 generic代码及说明:/** philosopherEating.cpp** Author: 郭浩东,梁仲海*/#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <pthread.h>#include <semaphore.h>#include <string.h>//共有5个哲学家#define PEOPLE_NUM 5//思考状态#define THINKING 1//饥饿状态#define HUNGRY 2//吃的状态#define EATING 3//5根筷子sem_t chopsticks[PEOPLE_NUM];//有一把互斥锁pthread_mutex_tmutex;void *philosopher(void *arg){//对于某个哲学家,id号int id = (int) arg;//初始状态设置为THANKINGint state = THINKING;int right = (id + 1) % PEOPLE_NUM;//右边的哲学家idint left = (id + PEOPLE_NUM - 1) % PEOPLE_NUM;//左边的哲学家id charptrState[32];//5个哲学家不断争夺资源while(1){switch(state){case THINKING:usleep(300);//如果是思考状态,则思考300usstate = HUNGRY;//变为饥饿状态strcpy(ptrState,"Thinking before eat");break;case HUNGRY:strcpy(ptrState,"Hungry");if(sem_wait(&chopsticks[left]) == 0){//阻塞状态if(sem_trywait(&chopsticks[right]) == 0){//非阻塞strcpy(ptrState,"I will Eating");state = EATING;}else{state = THINKING;strcpy(ptrState,"I have not chopsticks");sem_post(&chopsticks[left]);//释放请求的得到的left 筷子printf("Philosopher right chopsticks is busy,right=%d,thread id is %d\n",right,id);}}else{printf("Philosopher left chopsticks is busy,left=%d,thread id is %d\n",left,id);//这句话由于上面被阻塞永远不会输出}break;case EATING:printf("Philosopher fetch left and right chopsticks: (%d,%d), threadid is %d\n",left,right,id);sem_post(&chopsticks[left]);//释放左边的筷子sem_post(&chopsticks[right]);//释放右边的筷子printf("Philosopher release left and right chopsticks: (%d,%d), threadid is %d\n",left,right,id);usleep(500);state = THINKING;//吃完后继续转换为思考状态strcpy(ptrState,"Thinking after eat");break;}pthread_mutex_lock(&mutex);printf("Philosopher is %s, thread id is %d\n",ptrState,id);pthread_mutex_unlock(&mutex);usleep(1000);}pthread_exit((void*)0);}int main(){//存储5个哲学家的id号pthread_ttid[PEOPLE_NUM];inti;pthread_mutex_init(&mutex,NULL);//初始化互斥锁for(i = 0 ; i< PEOPLE_NUM ; i ++){sem_init(&chopsticks[i],0,1);//初始化资源型信号量}for(i = 0 ; i< PEOPLE_NUM ; i ++){pthread_create(&tid[i],NULL,philosopher,(void*)i);//创建5个线程代表5个哲学家,开始争夺筷子}for(i = 0 ; i< PEOPLE_NUM ; i ++){pthread_join(tid[i],NULL);//挂起}return 0;}运行结果截图:运行环境:windows10IDE:codeblocks代码及说明://哲学家就餐问题的解法#include <windows.h>#include <process.h>#include <time.h>#include <stdlib.h>#include <stdio.h>#include <iostream>using namespace std; //命名空间std内定义的所有标识符都有效const unsigned int PHILOSOPHER_NUM=5; //哲学家数目const char THINKING=1; /*标记当前哲学家的状态,1表示等待,2表示得到饥饿,3表示正在吃饭*/const char HUNGRY=2;const char DINING=3;HANDLE hPhilosopher[5]; //定义数组存放哲学家/*HANDLE(句柄)是windows操作系统中的一个概念。
围成圆形,中间站人的数学题
您提到的“围成圆形,中间站人”的数学题目可能是一个经典的数学问题,通常被称为“圆圈问题”或“哲学家就餐问题”。
这个问题描述了五个哲学家围坐在一张圆桌旁,每人面前有一根筷子。
哲学家们必须同时拿起两根筷子才能吃饭,但筷子必须在相邻的哲学家之间传递,因此可能出现所有哲学家都等待拿取第二根筷子而无法吃饭的情况。
这个问题是一个同步问题的实例,它揭示了在资源共享和互斥访问条件下的死锁问题。
在计算机科学中,死锁是指多个进程因为互相等待对方持有的资源而无限期地挂起的状态。
数学上,这个问题可以通过博弈论、逻辑、组合数学等多种方法进行分析。
例如,可以通过构造一个状态空间来分析所有可能的哲学家拿筷子的状态,并寻找避免死锁的策略。
为了解决这个问题,我们可以考虑以下策略:
1. 分配奇数个资源(在这个问题中是筷子)给哲学家。
这样,总是会有一个哲学家能够同时拿起两根筷子,因为总会有一个筷子是单独的。
2. 使用资源请求和释放的顺序规则。
例如,哲学家可以按照顺时针或逆时针的顺序请求筷子,确保他们不会同时请求相邻的筷子导致死锁。
3. 使用信号量或锁来控制对资源的访问。
通过使用P(等待)和V(信号)操作,可以实现对筷子的互斥访问,并避免死锁。
这个解决方案确保了哲学家们可以轮流就餐,避免了死锁的发生。
总之,您提到的“围成圆形,中间站人”的数学题目可能指的是哲学家就餐问题。
这个问题是一个经典的数学问题,通过博弈论、逻辑和组合数学等方法可以找到避免死锁的策略。
哲学家进餐问题5 个不讲卫生的哲学家围绕一张圆桌而坐,桌子上放着5 支筷子,每两个哲学家之间放一支;哲学家的动作包括思考和进餐,进餐时需要同时拿起他左边和右边的两支筷子,思考时则同时将两支筷子放回原处。
解法一:semaphore Fork[4]={0,1,2,3,4};philosopher_i(){Thinking;Being hungry;P(Fork[i mod 5]);P(Fork[(i + 1) mod 5]);Eating;V(Fork[i mod 5]);V(Fork[(i + 1) mod 5]);}这种解法存在问题,会导致死锁,假如5 个哲学家同时饥饿而各自拿左边的筷子时,会导致5 个筷子的信号量均为0,当他们试图拿右边的筷子时,都将因没有筷子而无限等待。
对于这种死锁问题,可以采用以下几种解决方法:1)仅当哲学家的左右筷子均可用时,才允许其进餐。
(即用AND 信号量机制解决)解法如下:Semaphore array[5]={1,1,1,1,1};Philosopher_i() //i=0,1,2,3,4{While(ture){Think;Sswait(chopstick[(i+1)mod5],chopstick[i]);Eat;Ssignal(chopstick[(i+1)mod5],chopstick[i]);}}2)规定奇数号哲学家先拿左边筷子,然后拿右边筷子;而偶数号哲学家相反。
解法如下:semaphore c[5]={1,1,1,1,1}; 初值均为1;philosopher_i() //i=0,1,2,3,4{If(i mod 2 != 0) //判断是否为奇数号哲学家{ //若为奇数号哲学家先拿左边筷子P(c[i]);P(c[i + 1] mod 5);Eating;V(c[i]);V(c[i + 1] mod 5);}else //若为偶数号哲学家先拿右边筷子{P(c[i + 1] mod 5);P(c[i]);Eating;V(c[i + 1] mod 5);V(c[i]);}}关于解决信号量问题的解题思路:主要是看看进程等的信号和要发出的信号是什么,理清思路。
实验描述:五个哲学家围成一圈,每两人之间有一支筷子。
五个哲学家任务(#1、#2、#3、#4、#5)主要有两种状态:思考(即睡眠一段时间)和就餐。
每个哲学家任务在就餐前必须申请并获得一左一右两支筷子,就餐完毕后释放这两支筷子。
任意一个哲学家在自己未拿到两只筷子吃饭前不会放下手中拿到的筷子。
一共有五支筷子,在该实验中用了五个互斥信号量来代表,每个信号量的初始值为1,当某个哲学家可以同时得到两根筷子(同时P两个信号量返回)时可以用餐,否则阻塞等待中。
用餐后需要同时V一下两个信号量,让其他进程可以P成功。
本实验在windows下进行。
源码:#include "stdio.h"#include "stdlib.h"#include "windows.h"#include "process.h"#include "iostream"using namespace std; //命名空间std内定义的所有标识符都有效#define N 5 //哲学家数目#define R(x) (x)//左边筷子#define L(x) ((x+1)%N)//右边筷子HANDLE hMutex[N]; //定义数组存放哲学家DWORD WINAPI MyThread(LPVOID lpParameter); //返回DWORD的API 函数voidpick_up(int me){if(me==0){WaitForSingleObject(hMutex[L(me)],INFINITE);//拿起左边的筷子printf("#%d pick up %d/n",me,L(me));Sleep(1000);WaitForSingleObject(hMutex[R(me)],INFINITE);//拿起右边的筷子printf("#%d pick up %d/n",me,R(me));Sleep(1000);}else{//防止死锁WaitForSingleObject(hMutex[R(me)],INFINITE);//拿起右边的筷子printf("#%d pick up %d/n",me,R(me));Sleep(1000);WaitForSingleObject(hMutex[L(me)],INFINITE);//拿起左边的筷子printf("#%d pick up %d/n",me,L(me));Sleep(1000);}}voidput_down(int me){ReleaseMutex(hMutex[R(me)]);//放下右边的筷子ReleaseMutex(hMutex[L(me)]);//放下左边的筷子}DWORD WINAPI MyThread(LPVOID lpParameter){int* me=(int *)lpParameter;pick_up(*me);Sleep(1000);printf("#%d is eating.../n",*me);put_down(*me);printf("#%d is thinking.../n",*me);return 1;}int main(intargc, char* argv[]){intThrdNo[5];DWORD dw;inti;for(i=0;i<N;i++)hMutex[i]=CreateMutex(NULL,FALSE,NULL);for(i=0;i<N;i++){ThrdNo[i]=i;CreateThread(NULL,0,MyThread,&ThrdNo[i],NULL,&dw); }Sleep(60000);return 0;}运行结果:可能一可能二结果分析:运行时可能交替出现两种结果。
java解哲学家就餐问题哲学家进餐问题是一个多线程运用的经典例子,涉及到线程同步/互斥,临界区访问问题以及一个避免死锁的解决方法。
有五个哲学家绕着圆桌坐,每个哲学家面前有一盘面,两人之哲学家进餐问题是一个多线程运用的经典例子,涉及到线程同步/互斥,临界区访问问题以及一个避免死锁的解决方法。
有五个哲学家绕着圆桌坐,每个哲学家面前有一盘面,两人之间有一支筷子,这样每个哲学家左右各有一支筷子。
哲学家有2个状态,思考或者拿起筷子吃饭。
如果哲学家拿到一只筷子,不能吃饭,直到拿到2只才能吃饭,并且一次只能拿起身边的一支筷子。
一旦拿起便不会放下筷子直到把饭吃完,此时才把这双筷子放回原处。
如果,很不幸地,每个哲学家拿起他或她左边的筷子,那么就没有人可以吃到饭了。
这就会造成死锁了。
这是需要坚决杜绝的,正如操作系统的死锁问题。
代码如下:import java.util.Random;public class DiningPhils{public static void main(String[] args){int n = 10;if( n < 1){System.err.println( "DiningPils <# of philosophers>" );System.exit(-1);}DiningPhils self = new DiningPhils();self.init(n);}public int getCount(){return n;}public void setChopstick( int i, boolean v){chops[ i ] = v;}public boolean getChopstick( int i ){return chops[i];}private void init( final int N){r = new Random();n = ( N < 0 || N > maxPhils ) ? maxPhils : N;chops = new boolean[n];phils = new Philosopher[n];initPhils();dumpStatus();}private void initPhils(){for( int i = 0; i< n; i++ ){phils[i] = new Philosopher( this, i );phils[i].setTimeSlice( generateTimeSlice());phils[i].setPriority( Thread.NORM_PRIORITY - 1);/**哲学家进程降低一级,使所有哲学家进程*全部初始化完毕前不会有哲学家进程抢占主线程*/}while( moreToStart() ){int i = Math.abs( r.nextInt()) % n;if( !phils[i].isAlive()){System.out.println( " ### Philosopher " +String.valueOf( i ) + " started.");phils[i].start();}}System.out.println( "\nPhilosophers Chopsticks" + "\n(1 = eating, 0 = thinking) (1 = taken, 0 = free)"); }public int generateTimeSlice(){int ts = Math.abs(r.nextInt()) % (maxEat + 1);if( ts == 0 )ts = minEat;return ts;}public void dumpStatus(){for( int i = 0; i < n; i++)System.out.print(phils[i].getEat() ? 1 : 0);for( int i = n; i < maxPhils + 4; i++ )System.out.print(" ");for( int i = 0; i < n; i++)System.out.print(chops[i]? 1:0);System.out.println();}private boolean moreToStart(){for( int i = 0; i < phils.length; i++ ){if( !phils[i].isAlive())return true;}return false;}private int n;private Philosopher[] phils;private boolean[] chops;private Random r;private static final int maxPhils = 24; //最多哲学家数 private static final int maxEat = 4; //最多进餐时间 private static final int minEat = 1; //最少进餐时间}class Philosopher extends Thread{public Philosopher( DiningPhils HOST , int i ){host = HOST;index = i;}public void setTimeSlice( int TS ){ts = TS;}public void setLeftChopstick( boolean flag ){host.setChopstick(index, flag);}public void setRightChopstick( boolean flag ){host.setChopstick((index + 1)% host.getCount() , flag);}private void releaseChopsticks(){setLeftChopstick(false);setRightChopstick(false);}public boolean chopsticksFree(){return !host.getChopstick(index) &&!host.getChopstick((index+1)%host.getCount());}public void run(){while(true){grabChopsticks();eat();think();}}private synchronized void grabChopsticks() /**临界区函数,确保哲学家在没有筷子或筷子不够时思考,满足条件后才就餐*/{while( !chopsticksFree()){try{wait();}catch( InterruptedException e){}}takeChopsticks();notifyAll();}private void takeChopsticks(){setLeftChopstick( true );setRightChopstick( true );setEat(true);host.dumpStatus();}private void eat(){pause();setEat( false );releaseChopsticks();}private void think(){pause();}private void pause(){setTimeSlice( host.generateTimeSlice());try{sleep(ts*1000);}catch( InterruptedException e){}}private void setEat(boolean v){isEating = v;}public boolean getEat(){return isEating;}private DiningPhils host;private boolean isEating;private int index;private int ts;}原文出处:中软卓越 。
世界十大经典逻辑题1. 乌龟爬井问题:一个乌龟掉进了井里,井里有30米深。
乌龟白天爬3米,晚上滑下2米。
问,这只乌龟需要多长时间才能爬出井口?2. 老虎过河问题:一个老虎和一只绵羊在河的一边。
河上有一条小船,但只能载一个动物过河。
老虎会吃绵羊,但只有老虎和绵羊同在河边时,才会发生危险。
如何将老虎和绵羊都安全地运到对岸?3. 渔夫问题:一个渔夫带着一只狼、一只羊和一堆鱼过河。
渔夫的船只能装下渔夫和另外一种动物或一堆鱼。
当狼和羊单独在一起时,狼会吃羊;当羊和鱼单独在一起时,羊会吃鱼。
渔夫如何安全地将所有物品都运到河的另一边?4. 三个开关问题:有三个开关,分别对应三个灯泡。
初始状态下,这三个灯泡都是关闭的。
你可以任意选择一个开关,打开它,然后等一会儿再关闭它。
然后,你可以再次选择一个开关,打开它或关闭它。
最后,你再次选择一个开关,打开它或关闭它。
问,通过这样的操作,你能否判断出每个开关分别控制的是哪个灯泡?5. 哲学家就餐问题:有五个哲学家坐在一个圆形桌子周围。
每个哲学家面前有一碗面条和一只叉子。
每个哲学家都喜欢思考和吃东西,但他们只有一只左手和一只右手,需要用叉子吃面条。
叉子在哲学家之间共享。
当一个哲学家同时拿着他左右两边的叉子时,他才能吃面条。
问,如何确保每个哲学家都能吃到面条,并防止死锁的发生?6. 水桶问题:你有两个容量分别为3升和5升的空桶。
你需要用这两个桶来测量出4升的水。
只有这两个空桶和一个水龙头。
问,你可以如何操作来实现这个目标?7. 分酒问题:有两个完全相同的杯子,一个里面装满了水,另一个是空的。
你需要将水平均分配到两个杯子中,但只能进行一次倒水动作。
问,你可以如何实现?8. 乘船问题:有三个大人和三个孩子需要乘一只小船过河。
而这只小船一次只能载两个人。
条件是,如果没有大人在场,两个孩子会打架;如果没有孩子在场,两个大人会互殴。
问,如何安排他们的乘船顺序,以使得所有人都能平安过河?9. 假币问题:有12枚硬币,其中有一枚是假币,但你不知道是假币比真币重还是轻。
哲学家就餐问题报告一、实验目的1、熟练使用VC6、0编译环境,调试并正确运行程序。
2、理解哲学家就餐问题中出现的问题,进而掌握死锁的必要条件。
3、理解源程序中产生和防止死锁的算法,及相关窗口操作。
4、熟悉哲学家就餐问题流程并写出其伪代码二、实验内容有五个哲学家围坐在一圆桌旁(如图1),桌中央有一盘通心粉,每人面前有一只空盘子,每两人之间放一只筷子。
每个哲学家的行为是思考,感到饥饿,然后吃通心粉。
为了吃通心粉,每个哲学家必须拿到两只筷子,并且每个人只能直接从自己的左边或右边去取筷子。
图1 图2三、实验要求1、程序需有防止死锁发生采取的措施;2、程序要有产生死锁的分配方式;四、实验算法实现1、不发生死锁的方式由源码gChopstickState[iLeftChopstick] = iPhilosopher; gChopstickState[iRightChopstick] = iPhilosopher;知基本思路是要么一下子占用两支筷子要么不占用,先确定两只筷子均没被占用才获取筷子,这样就打破了死锁的必要条件。
伪代码如下; var mutexleftchopstick,mutexrightchopstick; beging: resting; waiting; p(mutexleftchopstick); //先改变左手筷子信号量 p(mutexrightchopstick); //马上改变右手筷子信号量GetResource(leftchopstick,rightchopstick); //同时占用左右手筷子 eating; v(mutexleftchopstick); //释放资源v(mutexrightchopstick); end2、发生死锁的方式基本思路是有筷子即占用,看似效率很高,但因为资源有限,且不可抢占,很容易发生死锁。
源码理解: gDinerState[iPhilosopher] = WAITING;//wants chopsticks result = WaitForSingleObject(gchopStick[iLeftChopstick], INFINITE); gChopstickState[iLeftChopstick] = iPhilosopher; //得到左手筷子 Sleep(P_DELAY/4); //休眠状态gDinerState[iPhilosopher] = WAITING; //继续等待另一只手筷子 result =WaitForSingleObject(gchopStick[iRightChopstick], INFINITE); gChopstickState[iRightChopstick] = iPhilosopher; //直到等到右手筷子伪码书写:var mutexleftchopstick,mutexrightchopstick; beging: resting; waiting; p(mutexleftchopstick); //改变左手筷子信号量GetResource(leftchopstick); //获取左手筷子p(mutexrightchopstick); //改变右手筷子信号量GetResource(rightchopstick); //获取右手筷子 eating;v(mutexleftchopstick); v(mutexrightchopstick); end五、实验运行结果程序界面说明:通过位图句柄画演示的界面1.先画桌子,再画筷子,再画盘子,2.再画哲学家:哲学家用圆表示,根据哲学家的状态选择画笔(为resting 状态时为绿色圆圈,为等待或者,就餐时为红色圆圈)3.最后画哲学家的手:判断的依据是若筷子的编号和哲学家的编号一直致,那么认为这根筷子属于这个哲学家(筷子资源空闲)那么可以画手表示哲学家获得了这个筷子。
哲学家就餐问题——and型信号量机制仅当哲学家的左、右两只筷⼦均可⽤时,才允许他拿起筷⼦进餐以哲学家进餐模型为依据,在Linux控制台环境下创建5个进程,⽤semget函数创建⼀个信号量集(5个信号量,初值为1),模拟哲学家的思考和进餐⾏为:每⼀位哲学家饥饿时,先拿起左⼿筷⼦,再拿起右⼿筷⼦;筷⼦是临界资源,为每⼀⽀筷⼦定义1个互斥信号量;想拿到筷⼦需要先对信号量做P操作,使⽤完释放筷⼦对信号量做V操作。
实验平台:操作系统:CentOS 7编辑器:Gedit | Vim编译器:Gcc#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdint.h>#include <stdbool.h>#include <errno.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/ipc.h>#include <sys/sem.h>#include <sys/wait.h>#ifdef _SEM_SEMUN_UNDEFINEDunion semun{int val;struct semid_ds *buf;unsigned short *array;struct seminfo *__buf;};#endif#define ERR_EXIT(m) \do { \perror(m); \exit(EXIT_FAILURE); \} while(0)//相当于P操作int wait_1chopstick(int no,int semid){struct sembuf sb = {no,-1,0};int ret;ret = semop(semid,&sb,1);//semop()系统调⽤在semid标识的信号量集中的信号量上执⾏⼀个或多个up或down操作,可⽤于进程间的同步和互斥。