实验四模拟“五个哲学家”问题
- 格式:docx
- 大小:14.14 KB
- 文档页数:3
哲学家进餐问题问题描述:有5个哲学家共用一张圆桌,分别坐在周围的5张椅子上。
在桌上有5支筷子和5个碗,他们的生活方式是交替的进行思考和进餐。
平时,一个哲学家进行思考,饥饿时便试图取用他左右最靠近他的筷子,只有在他拿到两只筷子时才能进餐。
进餐完毕放下筷子继续思考。
解决方法:1)至多只允许4位哲学家同时去拿他左边的筷子,最终能保证至少有一个哲学家能够进餐,并在用毕时能够释放他用过的两支筷子,从而使更多的哲学家能够进餐。
2)规定奇数号哲学家先拿他左边的筷子然后再拿右边的筷子;而偶数号哲学家则与此相反。
3)仅当哲学家的左右两边的筷子都能用时才允许他拿起筷子进餐。
用第3)种方法解决代码如下:#include <stdio.h>#include <stdlib.h>#include <windows.h>#include <time.h>#define PHILOSOPHERS 5HANDLE gchopStick[PHILOSOPHERS];DWORD WINAPI PhilosopherThread(LPVOID pVoid) {HANDLE myChopsticks[2];DWORD result;int iPhilosopher = (int) pVoid;int iLeftChopstick = iPhilosopher;int iRightChopstick = iLeftChopstick + 1;if (iRightChopstick > PHILOSOPHERS-1)iRightChopstick = 0;myChopsticks[0] = gchopStick[iLeftChopstick];myChopsticks[1] = gchopStick[iRightChopstick];result=WaitForMultipleObjects(2,myChopsticks,TR UE,-1);printf("the %d PHILOSOPHER begin to eat\n",iPhilosopher);Sleep(200);printf("the %d PHILOSOPHER finishedeating",iPhilosopher);ReleaseMutex(myChopsticks[0]);ReleaseMutex(myChopsticks[1]);return EXIT_SUCCESS;}int main(int argc,char *argv[]){DWORD dwThreadId,wait_for_all;HANDLE hThread[PHILOSOPHERS];for (int i=0; i < PHILOSOPHERS; i++){gchopStick[i] = CreateMutex(NULL, FALSE, NULL);}for (i = 0; i < PHILOSOPHERS; i++)hThread[i] = CreateThread(NULL, 0, PhilosopherThread, (LPVOID) i, 0, &dwThreadId);wait_for_all=WaitForMultipleObjects(PHILOSOPHER S,hThread,TRUE,-1);printf("All PHILOSOPHERs finished eating\n");return 0; }。
课程设计题目进程同步模拟设计—哲学家就餐学院计算机科学与技术专业计算机科学与技术班级计算机姓名指导教师20011 年 1 月19 日需求分析1.1问题描述有五个哲学家围坐在一圆桌旁,桌中央有一盘通心粉,每人面前有一只空盘子,每两人之间放一只筷子,即共5只筷子。
每个哲学家的行为是思考和进餐。
为了进餐,每个哲学家必须拿到两只筷子,并且每个人只能直接从自己的左边或右边去取筷子。
思考时则同时将两支筷子放回原处(此图中以叉子代表筷子)规则:只有拿到两只筷子时,哲学家才能吃饭;如果筷子已经在他人手上,则该哲学家必须等到他人吃完之后才能拿到筷子;任何一个哲学家在自己没有拿到两只筷子吃饭之前,决不放下自己手中的筷子。
由此出现的问题:可能出现死锁问题,因为当五个哲学家都饥饿时,都拿着一支筷子,这样就可能五个哲学家都用不上餐1.2问题分析该问题可用记录型信号量或者是AND型信号量解决。
记录型信号量解决:经分析可知,放在桌子上的筷子是临界资源,在一段时间内只允许一位哲学家使用,为了实现对筷子的互斥使用,可以用一个信号量表示一只筷子,由这五个信号量组成信号量数组。
当哲学家饥饿时总是先拿其左边的筷子,成功后,再去拿右边的筷子,又成功后方可就餐。
进餐完,又先放下他左边的筷子,再放下右边筷子。
这个算法可以保证不会有两个相邻的哲学家同时就餐,但有可能引起死锁。
AND型信号量解决:在哲学家就餐过程中,要求每个哲学家先获得两个临界资源后方能就餐,这在本质上就是AND同步问题,故用AND信号量机制可获得最简洁的解法。
1.3解决方法对于死锁问题可采取这样的几种解决方法:(1)至多只允许四个哲学家同时进餐,以保证至少有一个哲学家可以进餐,最终总会释放出他所用过的两只筷子,从而可使更多的哲学家进餐;(2)仅当左右两只筷子均可用时,才允许哲学家拿起筷子就餐(3)规定奇数号哲学家先拿起右边筷子,然后再去拿左边筷子,而偶数号哲学家则相反。
(4)把筷子顺序编号 fk0, fk1, fk2, fk3, fk4,给每个哲学家分配筷子时,必须依从小号到大号(或者相反顺序)进行。
操作系统实验报告实验者:朱毅学号:0701013 实验题目:哲学家问题设有5个哲学家,共享一张放有5把椅子的桌子,每人分得一把椅子。
但是,桌子上总共只有5支筷子,在每人两边分开各放一支。
哲学家们在肚子饥饿时才试图分两次从两边拾起筷子就餐。
条件:(1)只有拿到两支筷子时,哲学家才能吃饭。
(2)如果筷子已在他人手上,则哲学家必须等他人吃完之后才能拿到筷子。
(3)任一哲学家在自己未拿到两支筷子吃饭之前,决不放下自己手中的筷子。
试:(1)描述一个保证不会出现两个邻座同时要求吃饭的通信算法。
(2)描述一个既没有两邻座同时吃饭,又没有人饿死(永远拿不到筷子)的算法。
(3)在什么情况下,5个哲学家全部吃不上饭?开发环境:Microsoft V isual Foxpro 6.0算法描述:数据环境:表KUAIZI 相应字段:筷子号状态(逻辑型)使用者桌号表ZHEXUEJIA相应字段:哲学家名所属状态拥有左筷子(逻辑型)拥有右筷子(逻辑型)桌号表FANGAN 相应字段方案表的具体内容请参见DAIMA.DOC文件本程序解决死锁的关键:从苏格拉底开始往黑格尔依次处理,对每人的处理一次进行到底,从而肯定必然有一人完全占有资源,避免了死锁,其实质就是按照5个哲学家的座位号作为绝对的优先级进行资源的先后分配。
初始状态:选择算法(以下两算法不同之处用黑体标识)算法一:(1)保证不会出现两个邻座同时要求吃饭的通信算法。
1、由操作人员按“有人饿了”按钮,控制是否有哲学家肚子饿了。
2、出现复选框和“确定”按钮,挑选哲学家后,按“确定”后确认选择。
当做出一个选择后,该哲学家左右两边的哲学家则不能被选中(通过对复选框的ENABLED属性控制),若取消选中,则该哲学家左右两边的哲学家(在该哲学家的另一邻居也未被选中为前提) 还原为可选状态。
3、“确认”后执行以下步骤:①从苏格拉底到黑格尔依次检验其是否是此次被选中②若是此次被选中,进行以下步骤:a 改变表KUAIZI 和表ZHEXUEJIA中相应的字段:ZHEXUEJIA:所属状态由F(Full)改为H(Hungry)b执行PROG1,分配给这些饥饿的哲学家筷子,若左边有筷子,取之,并标识“拥有左筷子”;若右边有筷子,取之,并标识“拥有右筷子”。
哲学家进餐问题2007/05/16 12:36 P.M./********************philosophers.cpp哲学家进餐问题在多线程中如何避免死锁。
问题描述:有五位哲学家围绕着餐桌坐,每一位哲学家要么思考要么等待,要么吃饭。
为了吃饭,哲学家必须拿起两双筷子(分别放于左右两端)不幸的是,筷子的数量和哲学家相等,所以每只筷子必须由两位哲学家共享下面是一种有问题的解法,因为在某个时刻,五个哲学家同时拿起五根左手边的筷子,则它们会在同一时候对待右手边的筷子,这样会陷入死锁,但是我测试了,这样的几率并不高经过几个小时,还没有出现。
但是我们可以肯定,理论上是肯定会出现死锁的,我们不能老是靠运气办事,怎么解决这个问题呢留给下一步的学习吧要编译此文件请用多线程版的c++库********************/#include <windows.h>#include <iostream>#include <process.h>#include <cstdlib>#include <ctime>using namespace std;unsigned int __stdcall philosopher(void *);void thinking(int);void eating(int);void wait_to_eat(int);void outline(int ,const char *);//全局变量CRITICAL_SECTION crout;//这个变量用来保证输出时不会竞争CRITICAL_SECTION fork[5];//定义五个临界变量,代表五更筷子int main(int argc,char *argv[]){void * hthread[5];int i;unsigned int threadid[5];int arg[5];int count = 5;unsigned long retval;InitializeCriticalSection(&crout);//初始化临界变量for(i=0;i<5;i++){InitializeCriticalSection(fork + i);}//创建五个哲学家for(i = 0; i<5;i++){arg[i] = i;hthread[i] = (void *)_beginthreadex(NULL,0,philosopher,(void *)(arg + i),0,threadid+i);if((int)hthread[i] == -1)//如果线程创建失败返回-1{cerr << "error while create thread " << i <<endl;cerr << "error code : "<< GetLastError() <<endl;}}//等待所有线程结束retval = WaitForMultipleObjects(5,hthread,true,INFINITE);//等待多个线程if(retval == WAIT_FAILED){cerr<< "wait error,error code: "<<GetLastError()<<endl;}for(i = 0; i<5;i++){if(CloseHandle(hthread[i]) == false)//关闭句柄{cerr << "error while close thread " <<i<<endl;cerr << "error code: "<<GetLastError()<<endl;}}return 0;}/*******************哲学家的行为吃饭,等待,思考*******************/unsigned int __stdcall philosopher(void *k){int n = ((int *)k)[0];outline(n," is in!");srand(time(NULL));while(true){thinking(n);wait_to_eat(n);eating(n);}outline(n," is out!");return n;}/*************思考随机一段时间*************/void thinking(int k){outline(k," is thinking...");Sleep((rand()%1000) *5);}/*************吃饭随机一段时间*************/void eating(int k){outline(k," is eating...");Sleep((rand()%1000) *5);LeaveCriticalSection(fork + (k+1)%5);//放下右边的筷子//outline(k," give left");LeaveCriticalSection(fork + k);//放下左边的筷子//outline(k," give right");}/***************等待吃饭需要同时获得他两边的筷子***************/void wait_to_eat(int k){outline(k," is waiting...");EnterCriticalSection(fork + k);//获得左边的筷子//outline(k," take left");EnterCriticalSection(fork + (k + 1)%5);//获得右边的筷子//outline(k," take right");}/********************//没有竞争条件的输出函数********************/void outline(int who,const char *str){EnterCriticalSection(&crout);cout<<"process "<<who<<str<<endl;LeaveCriticalSection(&crout);}/********************philosophers.cpp哲学家进餐问题在多线程中如何避免死锁。
哲学家进餐问题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); //退出房间释放信号量}}策略二原理:仅当哲学家的左右两支筷子都可用时,才允许他拿起筷子进餐。
哲学家就餐设有五个哲学家,共用一张放有五把椅子的餐桌,每人坐在一把椅子上,桌子上有五个碗和五只筷子,每人两边各放一只筷子。
哲学家们是交替思考和进餐,饥饿时便试图取其左右最靠近他的筷子。
条件:(1) 只有拿到两只筷子时,哲学家才能吃饭。
(2) 如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子。
(3) 任意一个哲学家在自己未拿到两只筷子吃饭前,不会放下手中拿到的筷子。
总体设计思想哲学家的生活就是思考和吃饭,即思考,饿了就餐,再思考,循环往复。
要求是:每一个哲学家只有在拿到位于他左右的筷子后,才能够就餐;哲学家只能先拿左边的筷子,再去拿右边的筷子,而不能同时去抓他两边的筷子,也不能从其他哲学家手中抢夺筷子;哲学家每次就餐后必须放下他手中的两把筷子后恢复思考,不能强抓住餐具不放。
设计一个程序,能够显示当前各哲学家的状态和桌上餐具的使用情况,并能无死锁的推算出下一状态各哲学家的状态和桌上餐具的使用情况。
即设计一个能安排哲学家正常生活的程序用0-4五个数字代表五位哲学家,0-4五的数字代表筷子。
模拟该问题。
问题描述可能出现死锁问题,因为当五个哲学家都饥饿时,都拿着一支筷子,这样就可能五个哲学家都用不上餐。
解决方案1 最多允许4个哲学家同时坐在桌子周围。
2 给所有哲学家编号,奇数号的哲学家必须首先拿左边的筷子,偶数号的哲学家则反之。
3 为了避免死锁,把哲学家分为三种状态,思考,饥饿,进食,仅当一个哲学家左右两边的筷子都可用时,才允许他拿筷子,并且一次拿到两只筷子,否则不拿。
程序截图1.开始选择界面2.选择“死锁”,则哲学家会按照先拿左边筷子,再拿右边筷子,而放筷子的时候也是同样的,因而会出现死锁,即光标不停闪烁,而程序不在继续的结果,如图3.选择“没有死锁”的界面,则是通过前面的解决方案对资源进行优化后,这样程序不会出现死锁,会一直运行,如图程序源代码:#include <windows.h>#include <conio.h>#include <stdlib.h>#include <stdio.h>#include <time.h>#include <io.h>#include <string.h>#define MAX_PHILOSOPHERS 5 //待测试的哲学家数#define ZERO 48 //数字0的ASCII码#define DELAY rand()%25HANDLEh_mutex_chopsticks[MAX_PHILOSOPHERS]; //互斥体数组,每根筷子需要一个互斥体intthread_number[MAX_PHILOSOPHERS]={0,1,2,3,4};//会产生死锁的哲学家线程int deadlock_philosopher(LPVOID data){int philosopher_number=*(int *)(data); //哲学家编号for(;;){srand( (unsigned)time( NULL ) * ( philosopher_number+ 1) );Sleep(DELAY);printf("%s%c%s%c\n","哲学家",ZERO+philosopher_number," 正在等待筷子",(ZERO+philosopher_number));WaitForSingleObject(h_mutex_chopsticks[philosopher_num ber], INFINITE);printf("%s%c%s%c\n","哲学家",ZERO+philosopher_number," 得到筷子",(ZERO+philosopher_number));Sleep(DELAY/4);printf("%s%c%s%c\n","哲学家",ZERO+philosopher_number," 正在等待筷子",(ZERO+(1+philosopher_number)%MAX_PHILOSOPHER S));WaitForSingleObject(h_mutex_chopsticks[((1+philosopher_n umber)%MAX_PHILOSOPHERS)], INFINITE);printf("%s%c%s%c\n","哲学家",ZERO+philosopher_number," 得到筷子",(ZERO+(1+philosopher_number)%MAX_PHILOSOPHER S));printf("%s%c%s\n","哲学家",ZERO+philosopher_number," 正在就餐.");Sleep(DELAY);ReleaseMutex(h_mutex_chopsticks[philosopher_number]);printf("%s%c%s%c\n","哲学家",ZERO+philosopher_number," 放下筷子",ZERO+philosopher_number);ReleaseMutex(h_mutex_chopsticks[(1+philosopher_number) %MAX_PHILOSOPHERS]);printf("%s%c%s%c\n","哲学家",ZERO+philosopher_number," 放下筷子",(ZERO+(1+philosopher_number)%MAX_PHILOSOPHER S));Sleep(DELAY);} // end forreturn 0;}//死锁时的初始化程序void deadlock(){int i=0;HANDLE h_thread[MAX_PHILOSOPHERS];printf("可能出现死锁的哲学家就餐问题\n");for(i=0;i<MAX_PHILOSOPHERS;i++){h_mutex_chopsticks[i]=CreateMutex(NULL,FALSE,NULL);};for(i=0;i<MAX_PHILOSOPHERS;i++){h_thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ ROUTINE)(deadlock_philosopher),&thread_number[i],0,NU LL);};WaitForMultipleObjects(MAX_PHILOSOPHERS,h_t hread,TRUE,-1);}//通过资源预分配法预防死锁的哲学家线程int pre_alloction_philosopher(LPVOID data){int philosopher_number=*(int *)(data);HANDLE h_mutex_leftandright_chopsticks[2];h_mutex_leftandright_chopsticks[0]=h_mutex_chopsti cks[philosopher_number];h_mutex_leftandright_chopsticks[1]=h_mutex_chopsticks[(1+ philosopher_number)%MAX_PHILOSOPHERS];for(;;){srand( (unsigned)time( NULL ) * ( philosopher_number+ 1) );Sleep(DELAY);printf("%s%c%s%c\n","哲学家",ZERO+philosopher_number," 正在等待筷子",ZERO+philosopher_number);printf("%s%c%s%c\n","哲学家",ZERO+philosopher_number," 正在等待筷子",ZERO+(1+philosopher_number)%MAX_PHILOSOPHER S);WaitForMultipleObjects(2,h_mutex_leftandright_chopsticks, TRUE, INFINITE);printf("%s%c%s\n","哲学家",ZERO+philosopher_number," 正在就餐.");Sleep(DELAY);printf("%s%c%s%c\n","哲学家",ZERO+philosopher_number," 放下筷子",ZERO+philosopher_number);ReleaseMutex(h_mutex_chopsticks[philosopher_number]);printf("%s%c%s%c\n","哲学家",ZERO+philosopher_number," 放下筷子",ZERO+(1+philosopher_number)%MAX_PHILOSOPHER S);ReleaseMutex(h_mutex_chopsticks[(1+philosopher_number) %MAX_PHILOSOPHERS]);Sleep(DELAY);} // end forreturn 0;}//通过资源预分配法预防死锁的初始化程序void pre_alloction(){int i=0;HANDLE h_thread[MAX_PHILOSOPHERS];printf("可能出现死锁的哲学家就餐问题\n");for(i=0;i<MAX_PHILOSOPHERS;i++){h_mutex_chopsticks[i]=CreateMutex(NULL,FALSE,NULL);};for(i=0;i<MAX_PHILOSOPHERS;i++){h_thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ ROUTINE)(pre_alloction_philosopher),&thread_number[i],0 ,NULL);};WaitForMultipleObjects(MAX_PHILOSOPHERS,h_t hread,TRUE,-1);}//主程序int main(int argc,char *argv[]){char select;while(1){printf("|-------------------------------------------------------------|\n");printf("| 1:死锁|\n");printf("| 2:没有死锁|\n");printf("| 3:退出|\n");printf("|--------------------------------------------------------------|\n") ;printf("请选择(1~3):");do{select=(char)getch();}while(select!='1'&&select!='2'&&select!='3');system("cls");switch(select){case '1':deadlock();break;case '2':pre_alloction();break;case '3':return 0;}printf("\nPress any key to return to main menu.");getch();system("cls");}return 0;}。
include <>include <>include <string>include <iostream>include <>using namespace std;bool tools5; //全局变量,用餐工具CRITICAL_SECTION cs; //信号量, 在线程中使用,临界区class Philosopher{private:int number;int status; /标记当前哲学家的状态,0表示正在等待即处于饥饿状态,1表示得到两支筷子正在吃饭,2表示正在思考/ public:Philosopherint num=0: status2, numbernum { }const int find{return number;}const int getinfo{ return status; }void Change ; //状态改变函数void dead_lock;};/////////void Philosopher::dead_lock{EnterCriticalSection &cs ; //进入临界区 string s;ifstatus==1{toolsnumber%5=true;// toolsnumber-1%5=true;status=2;}else ifstatus==2{status=0;//toolsnumber-1%5=false;//toolsnumber-1%5=true;}else ifstatus==0{toolsnumber%5=false;toolsnumber-1%5=false;status=1;}LeaveCriticalSection &cs ;// cout<<"";}/////////void Philosopher::Change{EnterCriticalSection &cs ; //进入临界区 ifstatus==1 //正在进餐{toolsnumber%5=true; //放下左手工具 toolsnumber-1%5=true; //放下右手工具 status=2; //改变状态为思考}else ifstatus==2 //思考中{status=0; //改变状态为等待}else ifstatus==0 //等待中{iftoolsnumber%5&&toolsnumber-1%5 //左右手两边工具均为空闲状态{toolsnumber%5=false; //拿起左手工具toolsnumber-1%5=false; //拿起右手工具status=1;}}LeaveCriticalSection &cs ;}string printPhilosopher pA{//pA->Change;int i=pA->getinfo;string str;ifi==0str="等待";else ifi==1str="就餐";else str="思考";return str;}string toolstatusbool a{string state;ifa==truestate="闲";ifa==falsestate="用";return state;}int main{char con='y'; //判断是否继续// con = 'n';forint i=0;i<5;i++toolsi=true; //筷子都未使用,初始化Philosopher P11,P22,P33,P44,P55;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<<"筷子的状态,用表示使用中,闲表示空闲中;"<<endl;cout<<"--------------------------------------------------------------"<<endl ;//cout<<"哲学家们开始生活:"<<endl;//cout<<"当前状态:";cout<<endl;//cin>>con;whilecon=='y'{; ; ; ; ;cout<<"当前状态为:"<<endl;cout<<" "<<<<print&P1<<" "<<endl;cout<<" "<<toolstatustools0<<" "<<toolstatustools1<<endl;cout<<" "<<<<print&P5<<" "<<<<print&P2<<endl;cout<<" "<<toolstatustools4<<" "<<toolstatustools2<<endl;cout<<" "<<<<print&P4<<" "<<<<print&P3<<endl;cout<<" "<<toolstatustools3<<endl;cout<<"--------------------------"<<endl;cout<<"若要继续下一状态,输入y;输入n进入死锁;输入其他,结束程序:";cin>>con;Sleep20;}whilecon=='n'{;; ; ; ;cout<<"死锁情况"<<endl;cout<<" "<<<<print&P1<<" "<<endl;cout<<" "<<toolstatustools0<<" "<<toolstatustools1<<endl;cout<<" "<<<<print&P5<<" "<<<<print&P2<<endl;cout<<" "<<toolstatustools4<<" "<<toolstatustools2<<endl;cout<<" "<<<<print&P4<<" "<<<<print&P3<<endl;cout<<" "<<toolstatustools3<<endl;cout<<"--------------------------"<<endl;cout<<"输入n继续;输入其他,结束程序:";cin>>con;Sleep20;}DeleteCriticalSection &cs ; //退出资源区return 0;}。
实验描述:五个哲学家围成一圈,每两人之间有一支筷子。
五个哲学家任务(#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;}运行结果:可能一可能二结果分析:运行时可能交替出现两种结果。
实验四模拟"五个哲学家"问题魏陈强学号:23020092204168谢思发学号:23020092204174一、实验题目:哲学家就餐问题是一种典型的同步问题,它是由Dijkstra提出并解决的。
该问题描述如下:有五个哲学家围坐在一张圆形餐桌,交替做以下两件事:吃饭和思考。
餐桌中间有一碗意大利面,每两个哲学家之间只有一支餐叉,如果他们想吃面则必须使用其左右的两支餐叉。
显然每次最多只能有2个哲学家同时进餐,而且进餐过程有可能会产生死锁,如每个哲学家都拿着左手餐叉,等待右手餐叉。
从而导致五个哲学家无法进餐而饿死。
现需实验模拟解决哲学家进餐问题,使哲学家们能顺利的进餐思考。
二、算法分析:该实验的要点是,解决并发环境下,多进程之间的同步与互斥问题。
进程间的同步互斥必然涉及进程间通信。
但是进程的内存空间是彼此隔离的,因此它们之间的通信只能通过如下手段:IPC机制、管道、信号或文件。
本次实验采用文件手段解决通信问题。
经验证如果哲学家中同时存在左撇子和右撇子,则哲学家问题有解。
模拟程序的框架如下所示:定义5个文件,分别表示5个叉子。
其文件名按如下方式说明:Static char* forks[5]={"fork0","fork1","fork2","fork3","fork4"};哲学家的行为可以用如下函数描述:Void philosopher(int i){while(1){thinking(i,nsecs);TakeFork(i);eating(i,nsecs);putFork(i);}}在主程序里,可以用以下的程序段生成5个哲学家进程:#define N 5for(i=0;i<N;i++){pid=fork();If(pid==0)philosopher(i);}wait(NULL);拿起叉子可以如此定义:void takeFork(i){if(i==N-1){lock(forks[0]);lock(forks[i]);else {lock(forks[i]);lock(forks[i+1]);}}放下叉子可以如此定义:void putFork(i){if(i==N-1){unclolck(forks[0]);unlock(forks[i]);}else{unlock(forks[i]);unlock(forks[i+1]);}}三、详细代码#include "apue.h"#include <sys/wait.h>#include <string.h>#include "lock.h"#include <stdlib.h>#define N 5int main(int argc,char *argv[]){int time,i;pid_t pid[5];static char* forks[5] = {"fork0","fork1","fork2", "fork3", "fork4"}; if(argc==2)time=atoi(argv[1]);elseerr_sys("error!");for(i=0;i<N;i++)unlock(forks[i]);for(i = 0; i < N; i++){pid[i] = fork();if( pid[i] == 0 ){while(1){printf("The %d philosopher is thinking\n",i);sleep(time);if( i == N - 1 ){lock( forks[0] );lock( forks[i] );}else{lock( forks[i] );lock( forks[i + 1] );}printf("The %d philosopher is eating\n",i);sleep(time);if( i == N - 1 ){unlock( forks[0] );unlock( forks[i] );}else{unlock( forks[i] );unlock( forks[i + 1] );}}}// if(waitpid(pid[i],NULL,0)!=pid[i])// err_sys("waitpid error");}wait(NULL);exit(0);}四、实验结果四、心得体会:这次实验总体来说偏难,整个过程不太顺利。
进程同步、互斥--哲学家进餐问题1、问题描述⼀张圆桌上有5名哲学家,没两个哲学家之间有⼀根筷⼦,桌⼦中间由⼀碗⽶饭。
当哲学家饥饿时会试图分别拿起左右两根筷⼦,如果筷⼦已在他⼈⼿上则需等待。
饥饿的哲学家只有拿起两根筷⼦才能进餐,吃完后才能放下筷⼦。
2、问题分析对哲学家分别编号0,1,2,3,4,对筷⼦编号0,1,2,3,4。
i号哲学家左边筷⼦编号为i,右边编号为(i+1)%5。
(1)⽅案1最多允许4个哲学家同时申请进餐,这样可以保证⾄少有⼀个哲学家有两根筷⼦(2)⽅案2要求奇数号的哲学家先拿左边的筷⼦,然后拿右边的筷⼦,偶数号哲学家相反semaphore chopstick[5]={1,1,1,1,1};Pi(){while(1){if(i%2!=0){P(chopstick[i]);P(chopstick[(i+1)%5]);}else{P(chopstick[(i+1)%5]);P(chopstick[i]);}进餐V(chopstick[i]);V(chopstick[(i+1)%5]);}}(3)⽅案3仅当哲学家两边的筷⼦都可以拿起的时候才能申请进餐semaphore chopstick[5]={1,1,1,1,1};semaphore mutex=1;Pi(){while(1){P(mutex);P(chopstick[i]);P(chopstick[(i+1)%5]);V(mutex);吃饭V(chopstick[i]);V(chopstick[(i+1)%5]);}}。
实验四模拟“五个哲学家”问题张冰22920132203923 2015/11/3一.实验目的学习和掌握并发进程同步的概念和方法。
二.实验内容1. 程序语法philosopher [ -t <time> ]<time>是哲学家进餐和沉思的持续时间值,缺省值为2秒。
2. 五个哲学家的编号为0~4,分别用五个进程独立模拟。
3. 程序的输出要简洁,仅输出每个哲学家进餐和沉思的信息。
例如,当编号为3的哲学家在进餐时,就打印:philosopher 3 iseating而当他在沉思时,则打印:philosopher3 is thinking除此之外不要输出其他任何信息。
4. 利用课堂已教授的知识而不使用线程或IPC机制进行同步。
5. 程序应该一直运行,直到人为地终止它(按Ctrl-C或Ctrl-\)。
不允许出现僵尸进程。
三.实验过程1.用for循环和fork函数生成5个哲学家进程,如果是前4个哲学家,思考<time>秒后,锁住左手边和右手边的叉子,然后开始用餐,进餐<time>秒后,释放两边的叉子,然后到下一个哲学家,用lock判断能否同时拿起两边的叉子,要是不能同时拿起则一直等待。
第5个哲学家最后应拿起第4把叉子和第0把叉子,用while(1)循环使程序一直运行。
2.lock(): 同时指定open()的O_CREAT 和O_EXCL 位,可用于判断文件是否存在(书中第48页)。
fd<0表示文件已存在,于是sleep1秒,然后继续尝试。
如果文件不存在,则创建文件,创建后,别人则无法再创建该文件。
通过这样的方式来模拟lock,即该叉子(文件)已被某哲学家(进程)使用(创建),在叉子未放下(未删除)前,其他人不能使用(创建)。
对应的unlock()就是删除该文件。
3.程序所需要的lock()、unlock()、putFork()、takeFork()等函数都已经给了出来,还有防止“死锁”的几种方法,所以主要做的就是main()函数的编写。
哲学家就餐问题python哲学家就餐问题是一个经典的并发问题,主要涉及到五个哲学家坐在圆桌旁,只有五支筷子,他们思考、拿起筷子、放下筷子都需要时间。
如果两个哲学家同时拿起相邻的两只筷子,就会死锁,因为总会有一个哲学家等待另一只筷子。
以下是一个Python实现的例子:python复制代码import threadingimport randomclass DiningPhilosophers:def__init__(self, n):self.forks = [threading.Lock() for _ in range(n)]self.philosophers = [threading.Thread(target=self.think_and_eat, args=(i,)) for i in range(n)]for philosopher in self.philosophers:philosopher.start()def think_and_eat(self, i):while True:self.think(i)self.eat(i)def think(self, i):print(f"Philosopher {i} is thinking")time.sleep(random.random()) # Thinking takes timedef eat(self, i):left = (i - 1) % 5# Left forkright = (i + 1) % 5# Right forkprint(f"Philosopher {i} is eating")with self.forks[left], self.forks[right]: #拿起左右两边的叉子time.sleep(random.random()) # Eating takes timeprint(f"Philosopher {i} is done eating")# 运行5个哲学家dining_philosophers = DiningPhilosophers(5)在这个实现中,我们使用了Python的threading模块来创建和运行线程,并且每个哲学家都有自己的思考和吃饭的线程。
题目:哲学家进餐5 个沉默寡言的哲学家围坐在圆桌前,每人面前一盘意面。
叉子放在哲学家之间的桌面上。
(5 个哲学家,5 根叉子)所有的哲学家都只会在思考和进餐两种行为间交替。
哲学家只有同时拿到左边和右边的叉子才能吃到面,而同一根叉子在同一时间只能被一个哲学家使用。
每个哲学家吃完面后都需要把叉子放回桌面以供其他哲学家吃面。
只要条件允许,哲学家可以拿起左边或者右边的叉子,但在没有同时拿到左右叉子时不能进食。
假设面的数量没有限制,哲学家也能随便吃,不需要考虑吃不吃得下。
设计一个进餐规则(并行算法)使得每个哲学家都不会挨饿;也就是说,在没有人知道别人什么时候想吃东西或思考的情况下,每个哲学家都可以在吃饭和思考之间一直交替下去。
问题描述和图片来自维基百科哲学家从0到4按顺时针编号。
请实现函数void wantsToEat(philosopher, pickLeftFork, pickRightFork, eat, putLeftFork, putRightFork):•philosopher哲学家的编号。
•pickLeftFork和pickRightFork表示拿起左边或右边的叉子。
•eat表示吃面。
•putLeftFork和putRightFork表示放下左边或右边的叉子。
•由于哲学家不是在吃面就是在想着啥时候吃面,所以思考这个方法没有对应的回调。
给你 5 个线程,每个都代表一个哲学家,请你使用类的同一个对象来模拟这个过程。
在最后一次调用结束之前,可能会为同一个哲学家多次调用该函数。
示例:输入:n = 1输出:[[4,2,1],[4,1,1],[0,1,1],[2,2,1],[2,1,1],[2,0,3],[2,1,2],[2,2,2], [4,0,3],[4,1,2],[0,2,1],[4,2,2],[3,2,1],[3,1,1],[0,0,3],[0,1,2],[0,2,2], [1,2,1],[1,1,1],[3,0,3],[3,1,2],[3,2,2],[1,0,3],[1,1,2],[1,2,2]]解释:n 表示每个哲学家需要进餐的次数。
问题描述:一个房间内有6位哲学家,他们的生活就是思考和进食。
哲学家思考后,过一定的时间就会饥饿,饥饿之后就想吃饭,吃饭后再思考。
房间里有一张圆桌,桌子周围放有6把椅子,分别属于6位哲学家,每两位哲学家之间有1支筷子,哲学家进食时必须同时使用左右两支筷子。
问题:1、写出哲学家进餐的算法描述。
philosopher(i);beginif(i%2!=0)//奇号哲学家{p((i+1)%6);p(i);eating;v(i+1);v(i);thinking;}else//偶号哲学家{p(i);p(i+1);eating;v(i);v(i+1);3thinking;}end2、写出你的算法如何解决死锁问题,即不能6位哲学家各拿到1支筷子,但都吃不上。
1)解决方案:让奇数号的哲学家先取右手边的筷子,让偶数号的哲学家先取左手边的筷子;这样、任何一个哲学家拿到一支筷子以后,就已经阻止了他的邻座的一个哲学家吃饭的企图(如1号哲学家由于他是奇号哲学家故先取右手边的2号筷子,当他取到2号筷子时就已经阻止了2号哲学家吃饭的企图、因为2号哲学家是偶号哲学家要想吃饭必需先拿到左手边的筷子2号筷子),在这种情况下除非某个哲学家一直吃下去,否则不会有人饿死。
2)这种排除死锁的方法属于死锁的预防即限制并发进程对资源的请求,从而使死锁的必要条件在系统执行的任何时间都不满足。
3、用C程序实现哲学家进餐。
(注:可以使用共享变量的方式,也可以使用信号量的方式来实现)#include<sys/types.h>#include<sys/sem.h>#include<sys/shm.h>#include<stdio.h>#include<stdlib.h>void vop(),pop();struct sembuf askfor_res,free_res;main(){int semid;int i;semid=semget(IPC_PRIVATE,6,0666|IPC_CREAT);//创建信号量集合printf("This sem number is %d\n",semid);for(i=0;i<6;i++)//初始化信号量{if(semctl(semid,i,SETVAL,1)==-1)perror("sem set value error");}int pid0,pid1,pid2,pid3,pid4,pid5;while((pid0=fork())==-1);if(pid0==0)//0号哲学家{while(1){pop(semid,0);//偶号哲学家先取左手边的筷子0pop(semid,1);//取右手边筷子printf("0 philosopher eating\n");sleep(1);vop(semid,0);vop(semid,1);printf("0 philosophers thought\n");sleep(3);}}else{while((pid1=fork())==-1);if(pid1==0)//1号哲学家{while(1){pop(semid,2);//奇号哲学家先取右手边的筷子pop(semid,1);//取左手边筷子1printf("1 philosopher eating\n");sleep(1);vop(semid,2);vop(semid,1);printf("1 philosophers thought\n");sleep(3);}}else{while((pid2=fork())==-1);if(pid2==0)//2号哲学家{while(1){pop(semid,2);//偶号哲学家先取左手边的筷子2 pop(semid,3);//取右手边筷子3printf("2 philosopher eating\n");sleep(1);vop(semid,2);vop(semid,3);printf("2 philosophers thought\n");sleep(3);}}else{while((pid3=fork())==-1);if(pid3==0)//3号哲学家{while(1){pop(semid,4);pop(semid,3);printf("3 philosopher eating\n");sleep(1);vop(semid,4);vop(semid,3);printf("3 philosophers thought\n");sleep(3);}}else{while((pid4=fork())==-1);if(pid4==0)//4号哲学家{while(1){pop(semid,4);pop(semid,5);printf("4 philosopher eating\n");sleep(1);vop(semid,4);vop(semid,5);printf("4 philosophers thought\n"); sleep(3);}}else{while((pid5=fork())==-1);if(pid5==0)//5号哲学家{while(1){pop(semid,0);pop(semid,5);printf("5 philosopher eating\n");sleep(1);vop(semid,5);vop(semid,0);printf("5 philosophers thought\n"); sleep(3);}}else{sleep(10);kill(0,15);exit(0);}}}}}}}void pop(int semid,int semnum)//P操作{int i;askfor_res.sem_num=semnum;askfor_res.sem_op=-1;askfor_res.sem_flg=SEM_UNDO;if((i=semop(semid,&askfor_res,1))==-1)perror("vop error.\n");}void vop(int semid,int semnum)//V操作{int i;free_res.sem_num=semnum;free_res.sem_op=1;free_res.sem_flg=SEM_UNDO;if((i=semop(semid,&free_res,1))==-1)perror("vop error.\n");}4、程序的运行结果。
一、问题描述:有五个哲学家围坐在一圆桌旁,桌中央有一盘通心粉,每人面前有一只空盘子,每两人之间放一只筷子每个哲学家的行为是思考,感到饥饿,然后吃通心粉.为了吃通心粉,每个哲学家必须拿到两只筷子,并且每个人只能直接从自己的左边或右边去取筷子二、本程序防止死锁发生采取的措施:仅当一个哲学家左右两边的筷子都可用时,才允许他拿筷子。
这样要么一次占有两只筷子(所有线程需要的资源)进行下一步的吃通心粉,然后释放所有的资源;要么不占用资源,这样就不可能产生死锁了。
三、产生死锁的分配方式:当筷子(资源)可用时,先分配左边的筷子,等待一会后再分配右边的筷子,由于这个过程中,左边的筷子一直没有释放,就有可能产生死锁了。
四、程序运行说明程序运行过程中会弹出一个MessageBox提示操作者操作:1.第一个对话框用于选择运行模式a.选择yes 表示采用的是运行的防止死锁的方式,这样的话整个程序可以一直运行下去,不会产生死锁。
b.选择no 表示运行产生死锁的方式会弹出第二个对话框。
2.第二个对话框用于选择运行时,线程运行的时间a. 选择 yes 线程时间比较短,很快就可以死锁b.选择no 线程时间跟选择yes 时候的时间差不多,产生死锁的时间稍微长一点五、关于哲学家就餐问题的mfc程序分析:A. Dining.c变量说明:函数说明:B.Mutex.c函数说明:1. DWORD WINAPI PhilosopherThread(LPVOID pVoid)哲学家进程:用于分配给哲学家筷子(资源)通过开始运行时候的对话框的选择来控制资源的分配方式:两中分配方式见二、三所述。
通过随机产生的时间来控制线程的运行,每个哲学家的状态都是resting waiting eating,一直循环。
2.int Diner(void)用于建立互斥的信号对象(筷子)和启动哲学家进程。
哲学家的晚餐
问题:
有5个哲学家坐在一个圆桌上。
食物摆在桌子中间,桌子上总共有5把叉子,每个哲学家的左右手各有一把。
因为吃饭时,哲学家需要同时使用左手和右手的叉子,所以哲学家必须和他左边和右边的哲学家共享叉子。
在这个实验中,假定哲学家每次吃饭的时间长度为单位1,吃完一次后则放下两把叉子。
如果等待10个单位时间长度之后,哲学家仍没有得到叉子吃饭,则被饿死。
你需要设计一种方法使得任何一个哲学家都不被饿死。
要求:使用ucos-ii操作系统设计一个应用程序,模拟5个哲学家的晚餐问题,要求5个哲学家都不能被饿死。
提示:
使用5个任务实现5个哲学家,哲学家的状态有思考、饥饿、晚餐。
每个哲学家先用哪个手取叉子随机确定。
用记录任务记录哲学家的等待时间。
实验四模拟"五个哲学家"问题
魏陈强学号:23020092204168
谢思发学号:23020092204174
一、实验题目:
哲学家就餐问题是一种典型的同步问题,它是由Dijkstra提出并解决的。
该问题描述如下:有五个哲学家围坐在一张圆形餐桌,交替做以下两件事:吃饭和思考。
餐桌中间有一碗意大利面,每两个哲学家之间只有一支餐叉,如果他们想吃面则必须使用其左右的两支餐叉。
显然每次最多只能有2个哲学家同时进餐,而且进餐过程有可能会产生死锁,如每个哲学家都拿着左手餐叉,等待右手餐叉。
从而导致五个哲学家无法进餐而饿死。
现需实验模拟解决哲学家进餐问题,使哲学家们能顺利的进餐思考。
二、算法分析:
该实验的要点是,解决并发环境下,多进程之间的同步与互斥问题。
进程间的同步互斥必然涉及进程间通信。
但是进程的内存空间是彼此隔离的,因此它们之间的通信只能通过如下手段:IPC机制、管道、信号或文件。
本次实验采用文件手段解决通信问题。
经验证如果哲学家中同时存在左撇子和右撇子,则哲学家问题有解。
模拟程序的框架如下所示:定义5个文件,分别表示5个叉子。
其文件名按如下方式说明:
Static char* forks[5]={"fork0","fork1","fork2","fork3","fork4"};
哲学家的行为可以用如下函数描述:
Void philosopher(int i)
{
while(1){
thinking(i,nsecs);
TakeFork(i);
eating(i,nsecs);
putFork(i);
}
}
在主程序里,可以用以下的程序段生成5个哲学家进程:
#define N 5
for(i=0;i<N;i++){
pid=fork();
If(pid==0)
philosopher(i);
}
wait(NULL);
拿起叉子可以如此定义:
void takeFork(i)
{
if(i==N-1){
lock(forks[0]);
lock(forks[i]);
else {
lock(forks[i]);
lock(forks[i+1]);
}
}
放下叉子可以如此定义:
void putFork(i)
{
if(i==N-1){
unclolck(forks[0]);
unlock(forks[i]);
}
else{
unlock(forks[i]);
unlock(forks[i+1]);
}
}
三、详细代码
#include "apue.h"
#include <sys/wait.h>
#include <string.h>
#include "lock.h"
#include <stdlib.h>
#define N 5
int main(int argc,char *argv[])
{
int time,i;
pid_t pid[5];
static char* forks[5] = {"fork0","fork1","fork2", "fork3", "fork4"}; if(argc==2)
time=atoi(argv[1]);
else
err_sys("error!");
for(i=0;i<N;i++)
unlock(forks[i]);
for(i = 0; i < N; i++)
{
pid[i] = fork();
if( pid[i] == 0 )
{
while(1)
{
printf("The %d philosopher is thinking\n",i);
sleep(time);
if( i == N - 1 )
{
lock( forks[0] );
lock( forks[i] );
}
else
{
lock( forks[i] );
lock( forks[i + 1] );
}
printf("The %d philosopher is eating\n",i);
sleep(time);
if( i == N - 1 )
{
unlock( forks[0] );
unlock( forks[i] );
}
else
{
unlock( forks[i] );
unlock( forks[i + 1] );
}
}
}
// if(waitpid(pid[i],NULL,0)!=pid[i])
// err_sys("waitpid error");
}
wait(NULL);
exit(0);
}
四、实验结果
四、心得体会:
这次实验总体来说偏难,整个过程不太顺利。
前期因为对多进程理解的不够透彻,导致出现各种错误。
后来详细地阅读了进程的相关章节后,才有一个较为清晰的思路。
另外在编写过程中还是会犯一些低级错误。
虽然大多是粗心所致,不过也说明自己编程不够熟练。
经过这次实验,对多进程之间的同步和互斥机制有了较好的认识,同时也意识到自身编程能力的不足。
需要在以后多多练习。