实验一 哲学家就餐问题

合集下载

哲学家进餐问题

哲学家进餐问题

哲学家进餐问题问题描述:有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; }。

哲学家进餐问题

哲学家进餐问题

哲学家进餐问题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-哲学家就餐问题

试验1-哲学家就餐问题

实验2. 类、对象、继承及多态实验目的:理解Java对象的面向对象的特征以及在编程中的应用。

实验内容:1、验证对象作为参数传递是引用传递,而普通数据类型为值传递。

2、验证构造方法和静态属性与方法专属于类,而其他属性和方法虽然在类中定义,但是为对象而定义。

3、验证子类对象实例化时,通过继承,不仅将public、protected、缺省的属性和方法拷贝到对象当中,也将父类的私有属性拷贝到对象当中。

4、编写程序,体会类在重载情况下的相互调用,体会构造方法重载的调用方式。

5、编程体现this的三种用法,super的两种用法,指出this.属性在什么情况下不可以省略,指出super.成员方法在什么情况下不能省略,指出this指代对象的作用。

6、设计Src和Dis两个类, Src中有一个被封装的属性,类型为int(要求为非负值),每当我们通过特定方法更改Src对象中的这个属性后,Dis对象都能得到通知,并向Src发消息获得此属性值实验要求:1、程序以能证明和说明实验内容当中提出的问题为实现标准。

2、程序应有良好的书写规范,在类名定义、包名定义、变量定义、常量定义上遵从规范,同时程序在书写上应有良好的缩进层次。

3、实验报告中应有实验体会和收获等方面。

准备工具:1、JDK1.3以上版本,设置环境变量,搭建编译和运行环境。

1、搭建环境。

2、选用Application进行验证。

实验3. 多线程综合设计实验目的:理解Java语言中的多线程和异常处理,并将二者结合起来设计一个综合程序,实现特定的应用功能。

实验内容:1、7名哲学家同桌就餐,演示哲学家就餐问题中死锁现象的出现,并说明原因2、给出一种解决方案,保证多线程下不出现死锁,并说明这样实现的理由实验要求:1、必须有多线程和异常的内容,其中多线程需要处理多线程同步,如还有同步通信则更好;异常需要有异常抛出、异常捕获、异常嵌套捕获等内容,如有自定义异常类则更好。

2、程序当中产生异常的点很多,在一个大的应用程序当中(有众多的类),无论哪种异常发生后,如何集中在一处统一给出中文提示。

哲学家就餐问题实验报告

哲学家就餐问题实验报告

哲学家就餐问题实验报告姓名:何绍金班级:自动化1202学号:201203870408指导教师:张健2014年11月22日一.实验题目经典的同步问题——哲学家就餐问题设计。

二.实验内容1.实验要求有五个哲学家围坐在一圆桌旁,桌中央有一盘通心粉,每人面前有一只空盘子,每两人之间放一只筷子每个哲学家的行为是思考,感到饥饿,然后吃通心粉.为了吃通心粉,每个哲学家必须拿到两只筷子,并且每个人只能直接从自己的左边或右边去取筷子。

2.程序流程图图1.主程序模块流程图开始定义信号量tools[5] 定义哲学家类对象P1-P5哲学家的状态发生改变;P1.change();P2.change();P3.change();P4.change();P5.change()输出当前状态停止程序结束否图2.状态改变模块流程图哲学家处于的状态否 哲学家处于思考状态是状态改为等待否 哲学家处于等待是 左右手筷子均空闲是 拿起左右手筷子状态改为就餐结束开始是 放下左右手工具 状态为思考 Status==2图3.返回哲学家状态流程图图4返回餐具状态模块流程图3.测试结果图5 测试结果1图6 测试结果2图7 测试结果34.结果分析和小结(1)程序分为四大模块,一步步解决了哲学家状态及状态改变的问题,筷子的“闲”、“用”问题;实现了哲学家等待、吃饭、思考三个过程的转换循环,并且避免了死锁问题;让临界资源得到了充分的利用。

(2)这次实验让我学会分模块解决问题,怎样运用互斥锁对临界资源进行管理;此外自己在编程上及一些函数的认识仍存在较大的问题,以后应该多多实践,提高自己的反应速度,加强逻辑思维能力。

三.程序源代码#include <windows.h>#include <time.h>#include <string>#include <iostream>#include <assert.h>using namespace std;bool tools[5]; //全局变量,用餐工具CRITICAL_SECTION cs; //信号量, 在线程中使用,临界区class Philosopher{private:int number;int status; /*标记当前哲学家的状态,0表示正在等待(即处于饥饿状态),1表示得到两支筷子正在吃饭,2表示正在思考*/public:Philosopher(int num=0): status(2), number(num) { }const int find(){return number;}const int getinfo(){ return status; }void Change() ; //状态改变函数void dead_lock();};/////////void Philosopher::dead_lock(){EnterCriticalSection (&cs) ; //进入临界区string s;if(status==1){tools[number%5]=true;// tools[(number-1)%5]=true;status=2;}else if(status==2){status=0;//tools[(number-1)%5]=false;//tools[(number-1)%5]=true;}else if(status==0){tools[number%5]=false;tools[(number-1)%5]=false;status=1;}LeaveCriticalSection (&cs) ;// cout<<"*********";}/////////void Philosopher::Change(){EnterCriticalSection (&cs) ; //进入临界区if(status==1) //正在进餐{tools[number%5]=true; //放下左手工具tools[(number-1)%5]=true; //放下右手工具status=2; //改变状态为思考}else if(status==2) //思考中{status=0; //改变状态为等待}else if(status==0) //等待中{if(tools[number%5]&&tools[(number-1)%5]) //左右手两边工具均为空闲状态{tools[number%5]=false; //拿起左手工具tools[(number-1)%5]=false; //拿起右手工具status=1;}}LeaveCriticalSection (&cs) ;}string print(Philosopher *pA){//pA->Change();int i=pA->getinfo();string str;if(i==0)str="等待";else if(i==1)str="就餐";else str="思考";return str;}string toolstatus(bool a){string state;if(a==true)state="闲";if(a==false)state="用";return state;}int main(){char con='y'; //判断是否继续// con = 'n';for(int i=0;i<5;i++)tools[i]=true; //筷子都未使用,初始化Philosopher P1(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<<"筷子的状态,用表示使用中,闲表示空闲中。

哲学家用餐问题

哲学家用餐问题

哲学家一(线程一函数)
读懂整 个程序。 请写出其余两个线程 的函数Thread2Proc 和 Thread3Proc ,使他们 都先取右边的筷子, 后取左边的筷子。执 行,写出实验结果或 现象。回答问题(3)
(2)描述一个既没有两座同时吃饭,又没有人饿死(永远拿 到到筷子)的算法。
• 对上面的程序Байду номын сангаас行改进,完成题目(2)要求。
选做题:
• 根据以前做过的实验,把算法移植到给定的图形用户界 面(GUI)框架程序中,每个线程创建自己的窗口,每个哲 学家的吃饭和取筷子信息显示在自己的窗口界面中,每 个窗口中右键单击时开始取筷子和吃饭的过程。 • 为降低图形化开发的难度,可以只设计三个哲学家线程, 每个线程设计自己的线程函数(即不合并线程函数)。 • 执行时以各种顺序在三个窗口中右击,验证执行结果。
• 思考:改变放下左右两边的筷子的顺序会有影 响吗?验证执行。
程序改进二: 把三个线程函数合并成一个统一的线程函数,哲学家的编号由 线程的函数参数传入,根据前面的程序代码完成省咯号处的设 计,并完成主函数的相应修改。执行,记录结果。
DWORD WINAPI ThreadProc( LPVOID lpParameter ) { int index; index=*(int *)lpParameter; …… return 0; } int main() { int num=1; h_Thread[0]=CreateThread(NULL,0 ,ThreadProc,&num ,0,NULL); num++; h_Thread[1]=CreateThread(NULL,0 ,ThreadProc,&num ,0,NULL); num++; h_Thread[2]=CreateThread(NULL,0 ,ThreadProc,&num ,0,NULL); }

哲学家就餐

哲学家就餐

哲学家就餐设有五个哲学家,共用一张放有五把椅子的餐桌,每人坐在一把椅子上,桌子上有五个碗和五只筷子,每人两边各放一只筷子。

哲学家们是交替思考和进餐,饥饿时便试图取其左右最靠近他的筷子。

条件:(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;}。

哲学家进餐问题-3中解决方案

哲学家进餐问题-3中解决方案

哲学家进餐问题-3中解决⽅案问题描述⼀张圆桌上坐着5名哲学家,每两个哲学家之间的桌上摆⼀根筷⼦,桌⼦的中间是⼀碗⽶饭,如图2-10所⽰。

哲学家们倾注毕⽣精⼒⽤于思考和进餐,哲学家在思考时,并不影响他⼈。

只有当哲学家饥饿的时候,才试图拿起左、右两根筷⼦(⼀根⼀根地拿起)。

如果筷⼦已在他⼈⼿上,则需等待。

饥饿的哲学家只有同时拿到了两根筷⼦才可以开始进餐,当进餐完毕后,放下筷⼦继续思考。

问题分析1) 关系分析。

5名哲学家与左右邻居对其中间筷⼦的访问是互斥关系。

2) 整理思路。

显然这⾥有五个进程。

本题的关键是如何让⼀个哲学家拿到左右两个筷⼦⽽不造成死锁或者饥饿现象。

那么解决⽅法有两个,⼀个是让他们同时拿两个筷⼦;⼆是对每个哲学家的动作制定规则,避免饥饿或者死锁现象的发⽣。

⼀共5个哲学家,编号0 ~4, 5⽀筷⼦编号也是0 ~4, 0号哲学家右⼿的筷⼦编号是0号,逆时针增加,哲学家的编号也是逆时针增加所以:0号哲学家对应的是: 4号和1号筷⼦.1号哲学家对应的是: 0号和2号筷⼦.2号哲学家对应的是: 1号和3号筷⼦.3号哲学家对应的是: 2号和4号筷⼦.4号哲学家对应的是: 3号和0号筷⼦.所以有宏定义:#define left(phi_id) (phi_id+N-1)%N#define right(phi_id) (phi_id+1)%NN = 55⽀筷⼦对应5个互斥锁,所以:pthread_mutex_t forks[N]={PTHREAD_MUTEX_INITIALIZER};哲学家线程需要执⾏的动作是:void take_forks(int id){//获取左右两边的筷⼦printf("Pil[%d], left[%d], right[%d]\n", id, left(id), right(id));pthread_mutex_lock(&forks[left(id)]);pthread_mutex_lock(&forks[right(id)]);//printf("philosopher[%d] take_forks...\n", id);}void put_down_forks(int id){printf("philosopher[%d] is put_down_forks...\n", id);pthread_mutex_unlock(&forks[left(id)]);pthread_mutex_unlock(&forks[right(id)]);}void* philosopher_work(void *arg){int id = *(int*)arg;printf("philosopher init [%d] \n", id);while(1){thinking(id);take_forks(id);eating(id);put_down_forks(id);}}该算法存在以下问题:当五个哲学家都想要进餐,分别拿起他们左边筷⼦的时候(都恰好执⾏完pthread_mutex_unlock(&forks[left(id)]);)筷⼦已经被拿光了,等到他们再想拿右边的筷⼦的时候(执⾏pthread_mutex_unlock(&forks[right(id)]);)就全被阻塞了,这就出现了死锁。

哲学家进餐问题

哲学家进餐问题
哲学家进餐问题
05611 贺美琛 冯文中
问题描述
设有五个哲学家,共用一张放有五把椅子 的餐桌,每人坐在一把椅子上,桌子上有五个 碗和五只叉子,每人两边各放一只叉子。哲学 家们是交替思考和进餐,饥饿时便试图取其左 右最靠近他的叉子。
(1) 只有拿到两只叉子时,哲学家才能吃饭。 (2) 如果叉子已被别人拿走,则必须等别人吃完之后才能拿 到叉子。
算法 C思想:
仅当哲学家的左右两支叉子都可用时, 才允许他拿起叉子进餐。
方法1:利用AND 型信号量机制实现 方法2:利用信号量mutex的保护机制实现
方法1
在一个原语中,将一段代码同时需 要的多个临界资源,要么全部分配给它, 要么一个都不分配,因此不会出现死锁 的情形。当某些资源不够时阻塞调用进 程;由于等待队列的存在,使得对资源的 请求满足FIFO 的要求,因此不会出现饥 饿的情形。
算法改善:
至多只允许四个哲学家同时进餐,以保 证至少有一个哲学家能够进餐,最终总会释 放出他所使用过的两支叉子,从而可使更多 的哲学家进餐。
改进后的算法A
semaphore fork[5]={1,1,1,1,1}; semaphore room=4; void philosopher(int i) { while(true) { think(); wait(room); //请求进入房间进餐 wait(fork[i]); //请求左手边的叉子 wait(fork[(i+1)%5]); //请求右手边的叉子 eat(); signal(fork[(i+1)%5]); //释放右手边的叉子 signal(fork[i]); //释放左手边的叉子 signal(room); //退出房间释放信号量room } }
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验一哲学家就餐问题
一、实验目的
1.熟练使用VC++6.0编译环境,调试并正确运行程序。

2.熟悉哲学家就餐问题流程。

3.理解哲学家就餐问题中出现的问题,进而掌握死锁的必要条件。

4.熟悉源程序中产生和防止死锁的算法,及其相关窗口操作。

二、实验原理
1.问题描述:
有五个哲学家围坐在一圆桌旁,桌中央有一盘通心粉,每人面前有一只空盘子,每
两人之间放一只筷子,每个哲学家的行为时思考,饥饿,然后吃通心粉,每个哲学
家必须拿到两只筷子,并且每个人只能直接从自己的左边或右边取筷子。

2.防止死锁发生的分配方式:
仅当一个哲学家左右两边的筷子都可用时,才允许他拿筷子。

这样要么一次占有两
只筷子(所有线程需要的资源)进行下一步吃通心粉,然后释放所有的资源;要么
不占用资源,这样就不可能产生死锁了。

3.产生死锁的分配方式:
当筷子(资源)可用时,先分配左边的筷子,等待一会后再分配右边的筷子,由于
这个过程中,左边的筷子一直没有释放,就可能产生死锁了。

4.程序运行说明:
程序运行过程中会弹出一个MessageBox提示操作者操作:
1)第一个对话框用于选择运行模式
a.选择yes表示采用的是运行的防止死锁的方式,这样的话整个程序可以一直运行下去,不会产生死锁。

b.选择no表示运行产生死锁的方式会弹出第二个对话框。

2)第二个对话框用于选择运行时,线程运行的时间
a.选择yes线程时间比较短,很快就可以死锁。

b.选择no线程时间跟选择yes时的时间差不多,产生死锁的时间稍微长一点。

三、实验过程及分析
1.PhilosopherThread(LPVOID pVoid)函数伪代码
1)不死锁方式
Var mutexleftchopstick,mutexrightchopstick;
Beging:
Resting;
Waiting;
P{mutexleftchopstick};
P{mutexrightchopstick};
GetResource{leftchopstick,rightchopstick};
Eating;
V{mutexleftchopstick};
V{mutexrightchopstick};
End
2)发生死锁方式
Var mutexleftchopstick,mutexrightchopstick;
Beging:
Resting;
Waiting;
P{mutexleftchopstick};
GetResource{leftchopstick};
P{mutexrightchopstick};
GetResource{rightchopstick};
Eating;
V{mutexleftchopstick};
V{mutexrightchopstick};
End
2.代码分析
1)不发生死锁时,哲学家迅速同时抢占两个筷子的资源,而若是不能同时抢占两只筷子则继续等待,知道有两只筷子空闲则抢占,这样就打破了死锁的必要条
件。

2)发生死锁时,因哲学家有左边的筷子空闲就抢占,再等待抢占右边的筷子,这样就有可能发生所有哲学家同时发现自己左边的筷子都空闲,都占用了左边的
筷子而等待右边的筷子,此时右边的筷子又都被别的哲学家占用,这样就进入
永远等待状态,即发生了死锁。

四、思考题
其他解决死锁方法:
1.引入一个对各个进程的调度者,当哲学家饥饿时向该调度者申请用餐,而调度
者根据哲学家面前是否同时有两只筷子空闲来判断哲学家此时能否就餐,能则
占用这两只筷子并且让哲学家就餐,不能则让哲学家继续等待。

引入一个调度
者能很有效地管理进程资源的分配。

2.可以让哲学家按一定顺序就餐,也可以避免死锁,但这样效率不高。

五、实验小结
通过这次上机实验,我对哲学家就餐问题有了更深入的了解,也学习到了具体C语言代码是如何实现这个问题的演示的。

同时更重要的是对资源的调度分配有了更深的思考,如何有效合理地分配资源,如何避免死锁,这都是我们再编写某些进程代码时需要考虑到的问题,而这次实验使我掌握了几种避免死锁的资源分配方法,对此我感到受益匪浅。

相关文档
最新文档