用多线程同步方法解决哲学家就餐问题报告

合集下载

操作系统课程设计利用多线程和信号量解决哲学家进餐问题java实现

操作系统课程设计利用多线程和信号量解决哲学家进餐问题java实现

操作系统课程设计利用多线程和信号量解决哲学家进餐问题j a v a实现IMB standardization office【IMB 5AB- IMBK 08- IMB 2C】操作系统课程设计课程设计报告课题:利用信号量和多线程机制实现“哲学家进餐”问题所在学院:信息工程学院班级:计科1201学号:4姓名:魏祥指导教师:徐向英2015年1月 1日目录一、课程设计目标 (3)二、课题内容 (3)三、设计思路 (3)四、源代码 (5)五、运行与测试 (9)六、心得体会 (10)一、课程设计目标学习多线程编程,使用线程的同步机制实现“哲学家进餐”问题。

具体要求:1.创建POSIX线程,实现多线程的并发执行,验证多线程共享进程资源的特性。

2.使用互斥量和条件变量,或使用信号量实现线程的同步互斥。

3.验证“哲学家进餐”问题中的死锁情况,并加以解决。

二、课题内容哲学家进餐问题由Dijkstra提出,问题描述有五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,他们的生活方式是交替地进行思考和进餐。

平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的筷子,只有在他拿到两只筷子时才能进餐。

进餐完毕,放下筷子继续思考。

本次课题要求使用多线程和信号量解决哲学家进餐问题。

并演示产生死锁的情况。

三、设计思路经分析可知,放在桌子上的筷子是临界资源,在一段时间内只允许以为哲学家使用。

为了实现对筷子的互斥,可以用一个信号量表示一只筷子,由着五个信号量构成信号量数组。

当哲学家饥饿时总是先去拿左筷子,成功后在拿右筷子。

当五位哲学家同时拿起左筷子,这是每位哲学家都没有右筷子可以拿,就会造成死锁。

思路1:利用记录型信号量设置值为4的记录型信号量,至多只允许四位哲学家同时去拿左筷子().acquire()),只有拿到左筷子,才能继续拿右筷子().acquire())。

拿到两双筷子之后便可以用餐,用餐完毕,先放下左筷子().release()),再放下右筷子().release())。

操作系统课程设计——哲学家进餐问题

操作系统课程设计——哲学家进餐问题

操作系统课程设计——哲学家进餐问题1000字哲学家进餐问题是一个经典的多线程同步问题,在操作系统中有着广泛的应用。

因此,在操作系统课程设计中,探究哲学家进餐问题是一件非常有意义的事情。

哲学家进餐问题的场景是:五个哲学家围坐在一张圆桌前,每个哲学家的左右两侧有一只筷子,他们需要利用这两只筷子才能进餐。

每个哲学家有两种状态:思考和进餐。

当一个哲学家处于进餐状态时,他需要同时获取他左右两侧的筷子,进餐结束后,他会释放这两只筷子,进入思考状态。

在这个场景中,如果所有的哲学家都同时想要进餐,那么就可能会出现死锁情况,即所有的哲学家都拿到了左手边的筷子,但都无法拿到右手边的筷子,导致无法进餐。

因此,需要在代码中实现同步互斥机制,避免死锁的发生。

本课程设计中,我使用了Java语言来实现哲学家进餐问题。

在代码实现中,首先定义了哲学家、筷子、餐桌等对象,然后使用线程来模拟哲学家的思考和进餐过程。

为了避免死锁,我使用了Chandy/Misra算法,即每个哲学家先尝试去取左手边的筷子,如果取不到就不再继续等待,而是重新回到思考状态,等待下一个机会。

同时,当一个哲学家取到了左手边的筷子之后,如果发现右手边的筷子已被占用,他就会释放左手边的筷子,重新回到思考状态,等待下一个机会。

在实现过程中,我还使用了信号量机制,保证了线程间的同步互斥。

每个筷子都是一个二元信号量,初始为1,表示可用。

当一个哲学家拿起筷子时,他会将对应的信号量减1,表示不可用。

当哲学家用完筷子之后,会将对应的信号量加1,表示可用。

通过这种方式,实现了对筷子的访问同步。

最后,我对代码进行了测试,模拟了多位哲学家同时进行进餐的过程。

在测试中,我发现哲学家进餐的速度受到筷子的数量和哲学家思考进餐比例的影响。

当筷子数量少于哲学家数量时,容易出现死锁;当哲学家思考和进餐的时间相当时,程序的运行情况比较稳定。

总的来说,本课程设计实现了哲学家进餐问题,通过学习该问题,我更深入地理解了同步互斥机制的重要性,并学会了如何使用信号量来实现同步互斥。

哲学家进餐问题

哲学家进餐问题

哲学家进餐问题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哲学家进餐问题在多线程中如何避免死锁。

操作系统课程设计利用多线程和信号量解决哲学家进餐问题java实现

操作系统课程设计利用多线程和信号量解决哲学家进餐问题java实现

操作系统课程设计课程设计报告课题:利用信号量和多线程机制实现“哲学家进餐”问题所在学院:信息工程学院班级:计科1201学号:121404114姓名:魏祥指导教师:徐向英2015年1月1日目录一、课程设计目标 (3)二、课题内容 (3)三、设计思路 (3)四、源代码 (5)五、运行与测试 (9)六、心得体会 (10)一、课程设计目标学习多线程编程,使用线程的同步机制实现“哲学家进餐”问题。

具体要求:1.创建POSIX线程,实现多线程的并发执行,验证多线程共享进程资源的特性。

2.使用互斥量和条件变量,或使用信号量实现线程的同步互斥。

3. 验证“ 哲学家进餐”问题中的死锁情况,并加以解决。

二、课题内容哲学家进餐问题由Dijkstra提出,问题描述有五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,他们的生活方式是交替地进行思考和进餐。

平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的筷子,只有在他拿到两只筷子时才能进餐。

进餐完毕,放下筷子继续思考。

本次课题要求使用多线程和信号量解决哲学家进餐问题。

并演示产生死锁的情况。

三、设计思路经分析可知,放在桌子上的筷子是临界资源,在一段时间内只允许以为哲学家使用。

为了实现对筷子的互斥,可以用一个信号量表示一只筷子,由着五个信号量构成信号量数组。

当哲学家饥饿时总是先去拿左筷子,成功后在拿右筷子。

当五位哲学家同时拿起左筷子,这是每位哲学家都没有右筷子可以拿,就会造成死锁。

思路1:利用记录型信号量设置值为4的记录型信号量,至多只允许四位哲学家同时去拿左筷子(leftStick.getSema().acquire()),只有拿到左筷子,才能继续拿右筷子(rightStick.getSema().acquire())。

拿到两双筷子之后便可以用餐,用餐完毕,先放下左筷子(leftStick.getSema().release()),再放下右筷子(rightStick.getSema().release())。

操作系统哲学家就餐问题实验报告

操作系统哲学家就餐问题实验报告

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;}。

利用AND信号量机制解决哲学家进餐问题

利用AND信号量机制解决哲学家进餐问题

利⽤AND信号量机制解决哲学家进餐问题哲学家就餐问题是1965年由Dijkstra提出的⼀种线程同步的问题。

问题描述:⼀圆桌前坐着5位哲学家,两个⼈中间有⼀只筷⼦,桌⼦中央有⾯条。

哲学家思考问题,当饿了的时候拿起左右两只筷⼦吃饭,必须拿到两只筷⼦才能吃饭。

上述问题会产⽣死锁的情况,当5个哲学家都拿起⾃⼰右⼿边的筷⼦,准备拿左⼿边的筷⼦时产⽣死锁现象。

解决办法: 1、添加⼀个服务⽣,只有当经过服务⽣同意之后才能拿筷⼦,服务⽣负责避免死锁发⽣。

2、每个哲学家必须确定⾃⼰左右⼿的筷⼦都可⽤的时候,才能同时拿起两只筷⼦进餐,吃完之后同时放下两只筷⼦。

3、规定每个哲学家拿筷⼦时必须拿序号⼩的那只,这样最后⼀位未拿到筷⼦的哲学家只剩下序号⼤的那只筷⼦,不能拿起,剩下的这只筷⼦就可以被其他哲学家使⽤,避免了死锁。

这种情况不能很好的利⽤资源。

package操作系统;class Philosopher extends Thread {private String name;private Fork fork;public Philosopher(String name, Fork fork) {super(); = name;this.fork = fork;}@Overridepublic void run() {thinking();fork.takeFork();eating();fork.putFork();}void eating() {System.out.println("I'm eating " + name);try {sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}void thinking() {System.out.println("I'm thinking" + name);try {sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}class Fork {boolean[] used = { false, false, false, false, false };synchronized void takeFork() {String threadName = Thread.currentThread().getName();String name = threadName.substring(threadName.length()-1, threadName.length());int i = Integer.parseInt(name);while (used[i] || used[(i + 1) % 5]) {try {wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}used[i] = true;used[(i + 1) % 5] = true;}synchronized void putFork() {String threadName = Thread.currentThread().getName();String name = threadName.substring(threadName.length()-1, threadName.length());int i = Integer.parseInt(name);used[i] = false;used[(i + 1) % 5] = false;notifyAll();}}public class哲学家就餐问题 {public static void main(String[] args) {Fork fork = new Fork();new Philosopher("1", fork).start();new Philosopher("2", fork).start();;new Philosopher("3", fork).start();;new Philosopher("4", fork).start();;new Philosopher("5", fork).start();;}}执⾏结果I'm thinking1I'm thinking3I'm thinking2I'm thinking4I'm thinking5I'm eating 1I'm eating 3I'm eating 5I'm eating 2I'm eating 4。

操作系统实验报告哲学家就餐

操作系统实验报告哲学家就餐

操作系统实验报告哲学家就餐一、实验目的:通过模拟哲学家就餐问题,了解并掌握操作系统中的进程同步机制,以及解决进程间资源竞争所引发的死锁问题。

二、实验介绍:哲学家就餐问题是由荷兰计算机科学家伊克斯特拉(Dijkstra)于1965年首次提出的。

其问题描述如下:五位哲学家坐在一张圆桌子周围,每个哲学家面前有一碗饭和一根筷子。

哲学家的生活方式是交替地进行思考和进食。

当一个哲学家思考时,他不需要使用他的两个筷子;当一个哲学家想吃饭时,他需要同时获取他的左右两个筷子,并在获取到筷子后才能开始进食。

问题的关键是如何解决哲学家间的筷子竞争问题,以及避免死锁的发生。

三、实验设计:1.并发思路每个哲学家作为一个进程,在进行思考和进食这两个操作之前,需要获取他的两个筷子。

接下来考虑进程同步的两个关键点:-互斥:保证每个筷子同时只能被一个哲学家使用,避免资源竞争问题。

-死锁避免:通过限制只允许至多四位哲学家同时持有筷子,从而避免死锁发生。

2.进程同步机制- 互斥:使用Semaphore实现互斥,每个筷子都是一个Semaphore,初始值为1-死锁避免:引入一个全局计数器,记录当前持有筷子的哲学家数量,每次哲学家想要获取筷子时,先检查该计数器,仅当计数器小于4时才会获取筷子。

四、实验步骤:1.创建5个哲学家进程和5个筷子线程。

2.每个哲学家的线程循环执行思考和进食操作。

3.在进食之前,哲学家需要获取两个筷子,获取筷子的顺序按照哲学家编号进行,每个哲学家先获取自己的左边筷子,再获取自己的右边筷子。

4.进行进食操作后,哲学家释放两个筷子。

5.循环执行步骤3和步骤4,直到实验结束。

五、实验结果:通过观察实验结果,可以看到哲学家的思考和进食操作交替进行,并且避免了死锁的发生。

六、实验总结:通过本次实验,我了解了操作系统中的进程同步机制,并学会了如何解决资源竞争和死锁问题。

在本实验中,我使用了Semaphore和全局计数器实现了互斥和死锁避免,从而成功模拟了哲学家就餐问题。

java解哲学家就餐问题

java解哲学家就餐问题

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;}原文出处:中软卓越 。

哲学家进餐问题

哲学家进餐问题

哲学家进餐问题————————————————————————————————作者:————————————————————————————————日期:哲学家进餐问题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哲学家进餐问题在多线程中如何避免死锁。

哲学家进餐问题

哲学家进餐问题
详细描述
死锁避免算法要求哲学家在取餐时按照固定的方向(顺时针或逆时针)进行。这 样,每个哲学家都只能等待其左侧或右侧的哲学家完成进餐后才能开始进餐。通 过这种方式,可以确保不会出现循环等待的情况,从而避免死锁的发生。
算法二:资源分级算法
总结词
资源分级算法通过优先满足更高级别的资源请求,避免死锁 的发生。
它被用来探讨多线程或多进程同步时可能出现的资源竞争和死锁情况。
问题的重要性
01
哲学家进餐问题是并发计算领域中的一个经典问题 ,对理解并发控制和同步机制至关重要。
02
解决哲学家进餐问题有助于避免死锁和资源竞争, 提高并发系统的可靠性和效率。
03
该问题还促进了并发算法和同步机制的研究,推动 了计算机科学的发展。
THANKS FOR WATCHING
感谢您的观看
哲学家进餐问题被视为并发控制领域的经典问题,它揭示了在并 发系统中资源访问冲突和死锁的可能性。
资源分配
该问题引发了对资源分配策略的深入研究,如何合理地分配资源以 避免冲突和死锁,成为计算机科学领域的重要议题。
算法设计
哲学家进餐问题为算法设计提供了一种挑战性的场景,促使研究者 设计出更高效、安全的并发算法和协议。
哲学家进餐问题
汇报人: 202X-01-05
contents
目录
• 问题的背景和起源 • 问题描述和模型建立 • 解决方案和算法 • 问题的影响和启示 • 问题的发展和未来方向
01
问题的背景和起源
问题的起源
哲学家进餐问题源于计算机科学和数学的交叉领域,特别是并发计算和同步问题。
该问题由艾兹赫尔·戴克斯特拉在1965年首次提出,旨在解决并发控制中的死锁问题 。

利用多线程实现哲学家就餐

利用多线程实现哲学家就餐

操作系统课程设计报告题目:利用多线程机制实现“哲学家就餐”所在学院:信息工程学院班级:计科1102学号:**********名:***指导教师:***日期: 2014 年 1 月 7日1.设计目的1.理解“哲学家就餐”模型,掌握基本的同步、互斥算法。

2.理解操作系统中进程和线程的异同,理解并发过程中的死锁现象。

3.掌握Linux多线程创建及并发机制、线程同步机制。

4.掌握和使用Linux POSIX线程接口实现无死锁的哲学家就餐问题。

2.需求分析2.1问题描述有五个哲学家围坐在一圆桌旁,桌中央有一盘通心粉,每人面前有一只空盘子,每两人之间放一只筷子,即共5只筷子。

每个哲学家的行为是思考和进餐。

为了进餐,每个哲学家必须拿到两只筷子,并且每个人只能直接从自己的左边或右边去取筷子。

思考时则同时将两支筷子放回原处(此图中以叉子代表筷子)规则:①只有拿到两只筷子时,哲学家才能吃饭;②如果筷子已经在他人手上,则该哲学家必须等到他人吃完之后才能拿到筷子;③任何一个哲学家在自己没有拿到两只筷子吃饭之前,决不放下自己手中的筷子。

由此出现的问题:可能出现死锁问题,因为当五个哲学家都饥饿时,都拿着一支筷子,这样就可能五个哲学家都用不上餐2.2问题分析该问题可用记录型信号量或者是AND型信号量解决。

记录型信号量解决:经分析可知,放在桌子上的筷子是临界资源,在一段时间内只允许一位哲学家使用,为了实现对筷子的互斥使用,可以用一个信号量表示一只筷子,由这五个信号量组成信号量数组。

当哲学家饥饿时总是先拿其左边的筷子,成功后,再去拿右边的筷子,又成功后方可就餐。

进餐完,又先放下他左边的筷子,再放下右边筷子。

这个算法可以保证不会有两个相邻的哲学家同时就餐,但有可能引起死锁。

AND型信号量解决:在哲学家就餐过程中,要求每个哲学家先获得两个临界资源后方能就餐,这在本质上就是AND同步问题,故用AND信号量机制可获得最简洁的解法。

2.3解决方法对于死锁问题可采取这样的几种解决方法:(1)至多只允许四个哲学家同时进餐,以保证至少有一个哲学家可以进餐,最终总会释放出他所用过的两只筷子,从而可使更多的哲学家进餐;(2)仅当左右两只筷子均可用时,才允许哲学家拿起筷子就餐(3)规定奇数号哲学家先拿起右边筷子,然后再去拿左边筷子,而偶数号哲学家则相反。

哲学家吃饭问题 实验报告 操作系统

哲学家吃饭问题 实验报告 操作系统

目录1.设计题目与要求 (2)设计目的设计要求2.总体设计思想与相关知识 (2)总体设计思想问题描述解决方案3.数据结构、流程图 (2)数据结构流程图4.源代码 (3)5.运行结果 (6)6.结果分析 (7)7.总结及心得体会 (7)1.设计题目与要求设计目的掌握进程同步问题的解决思路及方法,熟练使用Windows操作系统提供的信号量机制解决各种进程同步问题。

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

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

条件:(1) 只有拿到两只筷子时,哲学家才能吃饭。

(2) 如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子。

(3) 任意一个哲学家在自己未拿到两只筷子吃饭前,不会放下手中拿到的筷子。

2.总体设计思想与相关知识总体设计思想哲学家的生活就是思考和吃饭,即思考,饿了就餐,再思考,循环往复。

要求是:每一个哲学家只有在拿到位于他左右的筷子后,才能够就餐;哲学家只能先拿左边的筷子,再去拿右边的筷子,而不能同时去抓他两边的筷子,也不能从其他哲学家手中抢夺筷子;哲学家每次就餐后必须放下他手中的两把筷子后恢复思考,不能强抓住餐具不放。

设计一个程序,能够显示当前各哲学家的状态和桌上餐具的使用情况,并能无死锁的推算出下一状态各哲学家的状态和桌上餐具的使用情况。

即设计一个能安排哲学家正常生活的程序。

问题描述可能出现死锁问题,因为当五个哲学家都饥饿时,都拿着一支筷子,这样就可能五个哲学家都用不上餐。

解决方案最多允许4个哲学家同时坐在桌子周围。

给所有哲学家编号,奇数号的哲学家必须首先拿左边的筷子,偶数号的哲学家则反之。

为了避免死锁,把哲学家分为三种状态,思考,饥饿,进食,仅当一个哲学家左右两边的筷子都可用时,才允许他拿筷子,并且一次拿到两只筷子,否则不拿。

3.数据结构及流程图数据结构philosopherProc+myid:int+mystate:int+philosopherProc(LPVOIDlpParameter)+ResumeThread(hPhilosopher[i]):int+strcpy(stateStr, ""):int程序中定义一个哲学家类,包含两个私有对象和四个公有对象。

操作系统实验报告哲学家就餐

操作系统实验报告哲学家就餐

线程同步操作系统实验报告实验目的:1.理解和掌握Linux线程控制的系统调用命令。

2.理解和掌握Linux线程同步的系统调用命令。

实验内容:1.Linux线程机制pthread 相关系统调用命令:pthread_create,pthread_join,pthread_mutex_lock,pthread_mutex_unlock,enter_region,leave_region等。

2. 多线程编程使用线程同步机制实现Dinning Philosophers算法。

实验代码:#include<unistd.h>#include<assert.h>#include<stdio.h>#include<stdlib.h>#include<pthread.h>#define phi_num 5#define think_time 2#define eat_time 1#define left (phi_id+phi_num-1)%phi_num#define right (phi_id+1)%phi_numenum { think , hungry , eat } phi_state[phi_num];pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;pthread_mutex_t state[phi_num]={PTHREAD_MUTEX_INITIALIZER};void Do_think(int phi_id){printf(" philosopher %d is thinking now !\n",phi_id);sleep(think_time);}void Do_eat(int phi_id){printf("philosopher %d is eating now !\n",phi_id);sleep(eat_time);}void check_phi_state(int phi_id){if(phi_state[phi_id]==hungry&&phi_state[left]!=eat&&phi_state[right]!=e at){phi_state[phi_id]=eat;pthread_mutex_unlock(&state[phi_id]);}}void Do_take_forks(int phi_id){pthread_mutex_lock(&mutex);phi_state[phi_id]=hungry;check_phi_state(phi_id);pthread_mutex_unlock(&mutex);pthread_mutex_lock(&state[phi_id]);}void Do_put_forks(int phi_id){pthread_mutex_lock(&mutex);phi_state[phi_id]=think;check_phi_state(left);check_phi_state(right);pthread_mutex_unlock(&mutex);}void *philosopher(void *arg){int phi_id=*(int *)arg;while(1){Do_think(phi_id);Do_take_forks(phi_id);Do_eat(phi_id);Do_put_forks(phi_id);}return NULL;}int main(int argc, char *argv[]){int num;pthread_t *phi=(pthread_t*)malloc(sizeof(pthread_t)*phi_num);int *id=(int *)malloc(sizeof(int)*phi_num);for(num=0;num<phi_num;num++){id[num]=num;pthread_create(&phi[num],NULL,philosopher,(void*)(&id[num]));}for(num=0;num<phi_num;num++){pthread_join(phi[num],NULL);}return 0;}截图:。

Java哲学家进餐问题多线程

Java哲学家进餐问题多线程

Java哲学家进餐问题多线程J a v a实验三多线程哲学家进餐问题5个哲学家共⽤⼀张圆桌,分别坐在周围的5张椅⼦上,在圆桌上有5个碗和5只筷⼦(注意是5只筷⼦,不是5双),碗和筷⼦交替排列。

他们的⽣活⽅式是交替地进⾏思考(thinking)和进餐(eating)。

平时,⼀个哲学家进⾏思考,饥饿时便试图取⽤其左右最靠近他的两只筷⼦,规定他必须先取左边的筷⼦,再取右边的筷⼦。

只有在他拿到两只筷⼦时才能进餐。

进餐完毕,放下筷⼦继续进⾏思考。

假如5位哲学家同时饥饿,各⾃拿起左边的筷⼦时,再去拿各⾃右边的筷⼦,因为⽆筷⼦可拿⽽陷⼊⽆期限等待(死锁)。

进餐完毕释放他⽤过的两只筷⼦,从⽽使更多的哲学家能够进餐。

使⽤Java的多线程同步技术,实现上述解决⽅案。

解决⽅法⼀:破坏循环等待条件最多允许4个哲学家同时去拿左边的筷⼦,即死锁四⼤必要条件之⼀——破坏循环等待条件。

synchronized关键字易混淆处:⽤法:synchronized(⼀个对象){同步代码块}这⾥synchronized锁住的不是这"⼀个对象",⽽是⽤这"⼀个对象"来当看门⼈,只允许⼀个线程来进⼊synchronized锁住的同步{代码块},所以这个代码块被称作“同步代码块”,当代码块执⾏完后,会让这“⼀个对象”(看门⼈),吼⼀声让其它线程进来。

原理是:每⼀个java对象都关联了⼀个“ monitor lock”,当⼀个线程获取了 monitor lock 后,其它线程如果运⾏到获取同⼀个 monitor 的时候就会被 block 住。

当这个线程执⾏完同步代码,则会释放 monitor lock。

下⾯代码,经过分析后能满⾜最多允许4个哲学家同时去拿左边的筷⼦的条件:分析如下:1.如果不加num<4,synchronized(left)后,如果另⼀个哲学家进程拿了right的筷⼦,另⼀个哲学家⼜拿了这个哲学家右边的筷⼦...依此类推,产⽣循环等待链,即产⽣死锁。

哲学家就餐问题的算法实现

哲学家就餐问题的算法实现

哲学家就餐问题的算法实现哲学家就餐问题是一个经典的多线程并发问题,其目的是模拟几个哲学家在圆桌旁就餐的过程。

每个哲学家就坐在一个圆桌旁,桌上放有一个大盘子和五个筷子,其中每个哲学家需要两根筷子才能进食。

哲学家们通过轮流持有自己左右手两侧的筷子来进行进食和思考。

这个过程中需要避免死锁和饥饿等问题的产生。

在解决这个问题过程中,需要一个算法来保证生产者和消费者在访问共享资源时不会发生竞争和混乱,从而保证算法的正确性和高效性。

下面将介绍两种用于解决哲学家就餐问题的算法。

一、资源分级锁算法资源分级锁算法是这个问题最常用的解决算法之一。

该算法将筷子分为10个等级,并根据等级对筷子进行编号。

每个哲学家首先按照编号升序的顺序锁住自己左手边的筷子,然后锁住右手边的筷子,最后进食完成后按照相反的顺序进行解锁。

当哲学家需要获得筷子时,如果此时有高等级的哲学家在占用筷子,则需要等待。

例如,当哲学家1需要就餐时,他首先尝试获取编号1和2的筷子,如果此时筷子2被锁,则哲学家1需要等待。

当哲学家1成功获取筷子1和2之后,他开始进食,完成后按照相反的顺序解锁。

在资源分级锁算法中,每个哲学家都有机会获取到自己需要的筷子,同时还可以避免死锁和饥饿等问题的产生。

但是该算法需要进行大量的锁操作和对筷子进行编号,从而造成一定的开销和复杂度。

二、经典的信号量算法除了资源分级锁算法之外,还有一种叫做经典的信号量算法。

该算法使用信号量来对每个哲学家和筷子进行编号,并保证在每个时间点只有一个哲学家能够占用两个需要的筷子进行进食。

可以简单地理解为使用信号量来标识哪些筷子被占用,哪些筷子可以被使用。

当哲学家占用筷子时,需要调用P操作,释放锁时需要调用V操作。

当某个哲学家发现自己需要的筷子已被占用时,他就会进入等待状态,直到需要的筷子被释放为止。

例如,当哲学家1需要就餐时,他需要执行以下操作:1. P操作获取编号为1的筷子;2. P操作获取编号为2的筷子;3. 进食;4. V操作释放编号为1的筷子;5. V操作释放编号为2的筷子;在经典的信号量算法中,每个哲学家都只有在需要的筷子被空闲的情况下才能进食,从而避免了死锁和饥饿等问题。

多线程经典哲学家就餐问题C++113种实现

多线程经典哲学家就餐问题C++113种实现

多线程经典哲学家就餐问题C++113种实现哲学家就餐问题核⼼是 避免死锁1. 同时拿起左右叉⼦class DiningPhilosophers {public:DiningPhilosophers(){}void wantsToEat(int philosopher,function<void()> pickLeftFork,function<void()> pickRightFork,function<void()> eat,function<void()> putLeftFork,function<void()> putRightFork){int r =(philosopher+1)%5;mtx.lock();// 要么左右⼀起拿,要么都不拿lock[philosopher].lock();lock[r].lock();pickLeftFork();pickRightFork();mtx.unlock();eat();putRightFork();putLeftFork();lock[r].unlock();lock[philosopher].unlock();}private:std::mutex lock[5];std::mutex mtx;};2. 改变就餐策略(奇数先拿右,偶数先拿左)class DiningPhilosophers {public:DiningPhilosophers(){}void wantsToEat(int philosopher,function<void()> pickLeftFork, function<void()> pickRightFork, function<void()> eat,function<void()> putLeftFork, function<void()> putRightFork){ int l = philosopher;int r =(philosopher+1)%5;if(philosopher &1){lock[r].lock();lock[l].lock();pickRightFork();pickLeftFork();}else{lock[l].lock();lock[r].lock();pickLeftFork();pickRightFork();}eat();putLeftFork();putRightFork();lock[l].unlock();lock[r].unlock();}private:std::mutex lock[5];};3. 限定就餐⼈数(4个⼈就餐)class Semaphore {public:Semaphore(){}void set_count(int k){count = k;}void signal(){unique_lock<std::mutex>lock(mtx);++count;cv.notify_one();}void wait(){unique_lock<std::mutex>lock(mtx);while(count <=0)cv.wait(lock);--count;}private:int count;std::mutex mtx;std::condition_variable cv;};class DiningPhilosophers {public:DiningPhilosophers(){sem.set_count(4);}void wantsToEat(int philosopher,function<void()> pickLeftFork, function<void()> pickRightFork, function<void()> eat,function<void()> putLeftFork, function<void()> putRightFork){ int l = philosopher;int r =(philosopher+1)%5;sem.wait();lock[l].lock();lock[r].lock();pickLeftFork();pickRightFork();eat();putLeftFork();putRightFork();lock[l].unlock();lock[r].unlock();sem.signal();}private:Semaphore sem;std::mutex lock[5];};。

操作系统课程设计哲学家进餐问题报告

操作系统课程设计哲学家进餐问题报告

操作系统课程设计哲学家进餐问题报告课程设计报告(本科/专科)课程: 学号: 姓名: 班级: 教师: 时间:计算机科学与技术系操作系统课程设计2012.12. 7 -2013.1. 7设计名称:哲学家进餐问题设计内容、目的与要求:实验目的:通过实现哲学家进餐问题的同步深入了解和掌握进程同步和互斥的原理。

内容和要求:哲学家有N个,也定全体到达后开始讨论:在讨论的间除哲学家进餐,每人进餐时都需使用刀、叉各一把,所有哲学家刀和叉都拿到后才能进餐。

哲学家的人数、餐桌上的布置自行设定,实现刀和叉的互斥使用算法的程序实现。

计划与进度安排:设计过程、步骤(可加页):3.模块分析。

(1)主程序模块:昱(2)状态改变模块:(3)返回哲学家状态模块:等待状态的转换,餐具能够实现互斥。

设计体会与建议:经过了前后共2周的时间,我完成了这次课程设计。

通过这次课程设计,我学到了许多课本上学不到的知识,注意到了许多课本上没有提到的东西。

源程序代码#include <wlndows.h>#inclucle <string> #include <lostream> #include <assert.h> using namespace std; bool tools⑹;〃全局变量,用餐工具当一个线程执CRITICAL-SECTION cs; //>号量,在线程中使用,临界区,行了EnterCritialSection之后,cs里面的信息便被修改了,以指明哪一个线程占用了它。

class Philosopher{private:int number;Hit status; /*标记当前哲学家的状态,0表示正在等待(即处于饥饿状态),1表示得到两支筷子正在吃饭,2表示正在思考public:Philosopher(lnt num=0): status(2)9 number(num) { }int find() const { return number; }int getinfo() const { return status;}void Change(); 〃状态改变函数void Philosopher::Change(){EnterCriticalSection (&cs); 〃进入临界区if(statiis==l) 〃正在进餐{tools[number%6]=true; 〃放下左手工具tools[(number-l)%6]=true; 〃放下右手工具status=2; 〃改变状态为思考if(tools[niimber%6]&&tools[(number-1) % 6]) 〃左右手两边工具均为 空闲状态{tools[number%6]=false; 〃拿起左手工具 tools[(number-l)%6]=false; 〃拿起右手工具 status=l;LeaveCriticalSection (&cs);string print(Philosopher *pA){//pA->Change();int i=pA->getinfo();string str;if(i==O)St!•■等待";else lf(i==l)sW 就餐冷else if(status=2) status=O; else lf(status=O)〃思考中〃改变状态为等待else str=ft思考";return str;}string toolstatus(bool a){string state;if(a==true)state=n闲”;if(a==false)state=M用”;return state;}int main(){char con = *y'; 〃判断是否继续for(int i=0;i<6;i++)tools[i]=true; 〃3组刀叉都未使用,初始化Philosopher P1(1),P2(2),P3(3),P4(4),P5(5),P6(6);InitializeCriticalSection (&cs); 〃初始化初始化临界区cout«f,------------------ 状态说明示意图:------- cout«tf“vv"哲学家0号的状态”vv" cout«tf哲学家5号的状态“v V" "vv"叉3的状态”vv“f,«endl;t,«endl;y刀1“VV"哲学家1号的状态n«endl;cout«fln«H X i 的状态n«endl;cout«n<学家4号的状态”vv”"vv"叉2的状态"vv”tf«H刀2的状态”vv”“VB哲学家2号的状态tf«en(ll;cout«H"vv”哲学家 3 号的状态"vv”u«endl;coutvv"餐具的状态,用表示使用中,闲表示空闲中。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

课程设计报告书课程名称:计算机操作系统题目:用多线程同步方法解决哲学家就餐问题系名:专业班级:姓名:学号:指导教师:2016 年 6 月 24 日武汉华夏理工学院信息工程系课程设计任务书课程名称:操作系统原理课程设计指导教师:班级名称:开课系、教研室:自动化与计算机一、课程设计目的与任务操作系统课程设计是《操作系统原理》课程的后续实践课程,旨在通过一周的实践训练,加深学生对理论课程中操作系统概念,原理和方法的理解,加强学生综合运用操作系统原理、Linux系统、C语言程序设计技术进行实际问题处理的能力,进一步提高学生进行分析问题和解决问题的能力,包含系统分析、系统设计、系统实现和系统测试的能力。

学生将在指导老师的指导下,完成从需求分析,系统设计,编码到测试的全过程。

二、课程设计的内容与基本要求1、课程设计题目用多线程同步方法解决哲学家就餐问题2、课程设计内容本课程设计要求在Linux操作系统,GCC编译环境下开发。

用c/c++语言在Linux操作系统环境下,通过研究Linux的线程机制和信号量实现哲学家就餐问题的并发控制。

为避免死锁,可采用只许4个哲学家入席且桌上有5支筷子的办法。

几把椅子可用连续存储单元。

1 每个哲学家取得一双筷子开始用餐后,即时显示“Dining…”和该哲学家的标识符以及餐桌上有几位哲学家及其所坐的位置。

2 设定共有10个哲学家需用餐。

每位用餐耗时10秒钟以上。

3 多个哲学家须共享操作函数代码。

提示:1 有界缓冲区/连续存储区可用数组实现。

2 编译命令可用:gcc -lpthread -o 目标文件名源文件名3 多线程编程方法参见电子文档。

3、设计报告撰写格式要求:1设计题目与要求 2 设计思想3系统结构 4 数据结构的说明和模块的算法流程图5 使用说明书(即用户手册):内容包含如何登录、退出、读、写等操作说明6 运行结果和结果分析(其中包括实验的检查结果、程序的运行情况)7 自我评价与总结8 附录:程序清单,注意加注释(包括关键字、方法、变量等),在每个模块前加注释;三、课程设计步骤及时间进度和场地安排课程设计集中时间安排:四、课程设计考核及评分标准课程设计考核将综合考虑学生的系统设计方案、运行结果、课程设计报告书的质量、态度、考勤、答辩情况等各因素。

具体评分标准如下:(1)设计方案正确,具有可行性、创新性; 30分(2)系统开发效果较好; 20分(3)设计报告规范、课程设计报告质量高、参考文献充分 20分(4)课程设计答辩时,问题回答正确; 20分(5)态度认真、刻苦钻研、遵守纪律; 10分按上述五项分别记分后求和,总分按五级制记载最后成绩。

优秀(100~90分),良好(80~89分),中等(70~79分),及格(60~69分),不及格(0~59分)一、设计题目:用多线程同步方法解决哲学家就餐问题二、设计思想:1、为每个哲学家产生一个线程,设计正确的同步算法2、每个哲学家取得一双筷子开始用餐后,即时显示“Dining…”和该哲学家的自定义标识符以及餐桌上所有几位哲学家标识符及其所坐的位置。

3、设定共有10个哲学家需用餐。

每位用餐耗时10秒钟以上。

4、多个哲学家须共享操作函数代码。

三、系统结构四、主要数据结构的说明和模块的算法流程图:1、创建函数pthread_create声明如下:#include <pthread.h>Int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void*(*start_routine) (void *), void *arg);2、等待其它线程结束函数pthread_join声明如下:#include <pthread.h>int pthread_join(pthread_t thread, void **retval);3、信号量的数据类型为结构sem_t,它本质上是一个长整型的数。

初始化信号量函数sem_init声明如下:#include <semaphore.h>sem_init (sem_t *sem, int pshared, unsigned int value);4、增加信号量值函数sem_post声明如下:#include <semaphore.h>int sem_post(sem_t *sem);5、减少信号量值函数sem_wait声明如下#include <semaphore.h>int sem_wait(sem_t * sem);主要数据结构声明:1、#define NUMBERS 10 //将哲学家人数NUMBERS定义为102、sem_t chopstics[NUMBERS] //定义5只筷子的互斥信号量chopstics3、sem_t room //定义避免死锁的同步信号量room线程共享函数伪代码:void *Share(int i){think();p(room); //请求入席进餐p(chopstick[setnumber]); //请求左手边的筷子p(chopstick[setnumber+1]); //请求右手边的筷子eat();v (chopstick[setnumber]); //释放左手边的筷子v(chopstick[setnumber+1])); //释放右手边的筷子v(room); //退出席位释放信号量chairs}五、使用说明:打开虚拟机,进入linux系统。

应用程序—终端—输入gcc –lpthread –o a.a.c—编码成功后,输入./a ,得到所需结果。

六、运行结果和结果分析:如图1、2所示:图1图2[syh@localhost ~]$ gcc -lpthread -o a a.c [syh@localhost ~]$ ./a哲学家1坐上了位置1哲学家1拿到左侧筷子1哲学家1拿到右侧筷子2哲学家1坐在1椅子上吃饭dining……***************哲学家1坐在椅子1上————————————哲学家2坐上了位置2哲学家3坐上了位置3哲学家3拿到左侧筷子3哲学家3拿到右侧筷子4哲学家3坐在3椅子上吃饭dining……***************哲学家1坐在椅子1上哲学家2坐在椅子2上哲学家3坐在椅子3上————————————哲学家4坐上了位置4哲学家1吃饱了放下筷子1和2哲学家1离开了位置1走到一边画圈圈哲学家3吃饱了放下筷子3和4哲学家3离开了位置3走到一边画圈圈哲学家2拿到左侧筷子2哲学家2拿到右侧筷子3哲学家2坐在2椅子上吃饭dining……***************哲学家2坐在椅子2上————————————哲学家5坐上了位置1哲学家5拿到左侧筷子1哲学家4拿到左侧筷子4哲学家4拿到右侧筷子5哲学家4坐在4椅子上吃饭dining……***************哲学家5坐在椅子1上哲学家2坐在椅子2上————————————哲学家2吃饱了放下筷子2和3哲学家4吃饱了放下筷子4和5哲学家4离开了位置4走到一边画圈圈哲学家5拿到右侧筷子2哲学家5坐在1椅子上吃饭dining……***************哲学家5坐在椅子1上哲学家2坐在椅子2上————————————哲学家6坐上了位置3哲学家6拿到左侧筷子3哲学家6拿到右侧筷子4哲学家6坐在3椅子上吃饭dining……***************哲学家5坐在椅子1上哲学家2坐在椅子2上哲学家6坐在椅子3上————————————哲学家2离开了位置2走到一边画圈圈哲学家8坐上了位置2哲学家9坐上了位置4哲学家5吃饱了放下筷子1和2哲学家5离开了位置1走到一边画圈圈哲学家6吃饱了放下筷子3和4哲学家6离开了位置3走到一边画圈圈哲学家8拿到左侧筷子2哲学家8拿到右侧筷子3哲学家8坐在2椅子上吃饭dining……***************哲学家8坐在椅子2上————————————哲学家7坐上了位置1哲学家7拿到左侧筷子1哲学家9拿到左侧筷子4哲学家9拿到右侧筷子5哲学家9坐在4椅子上吃饭dining……***************哲学家7坐在椅子1上哲学家8坐在椅子2上————————————哲学家8吃饱了放下筷子2和3哲学家7拿到右侧筷子2哲学家7坐在1椅子上吃饭dining……***************哲学家7坐在椅子1上哲学家8坐在椅子2上————————————哲学家9吃饱了放下筷子4和5哲学家9离开了位置4走到一边画圈圈哲学家8离开了位置2走到一边画圈圈哲学家10坐上了位置3哲学家10拿到左侧筷子3哲学家10拿到右侧筷子4哲学家10坐在3椅子上吃饭dining……***************哲学家7坐在椅子1上哲学家10坐在椅子3上————————————哲学家7吃饱了放下筷子1和2哲学家7离开了位置1走到一边画圈圈哲学家10吃饱了放下筷子3和4哲学家10离开了位置3走到一边画圈圈七、测试过程及结果分析:各个哲学家(线程)完全独立自主运作,达到了预期的目标,拿筷子自然无冲突,吃饭也能正常运行,全程序没有一个哲学家饿死(线程不执行),或者是有哲学家在座位上却吃不到饭(死锁)的问题。

所有的哲学家都可以去画圈圈。

八、心得体会:虽然这次课程设计用了一星期,但是通过查阅资料,还是有了很大的收获,,使我对操作系统的基本知识有了进一步的提高,并在实践中对各种概念有了进一步的深化。

初看别人的编程,根本就不知道写的是什么。

只知道不停的运行,却一直得不到结果,坐着干着急。

后来,慢慢地从一点一滴的学习中,能够将程序读懂了,这就是最大的进步。

通过这次课程设计,我确实学到了很多东西,这些学到的东西可以使我受益终生。

除了知识技术上的东西,我更锻炼了自己的快速学习能力。

总的来说,这次的课程设计的收获比较大,对LINUX的运用以及编程都更进了一步。

一个看似小程序,却包含了很多辛劳,没有扎实的理论基础和熟练地操作是很难在短时间内完成作品的。

九、附录:#include <stdio.h>#include <unistd.h>#include <pthread.h>#include <semaphore.h>#define NUMBERS 10//设置哲学家数目sem_t chopstics[5];//设置筷子数目sem_t room; //设置房屋信号灯sem_t mutex;//设置互斥信号灯sem_t yourenmutex;//设置有人互斥信号灯int youren[5]={0,0,0,0,0};//设置是人变量int chairs[4]={1,2,3,4};//设置椅子int i,j;//设置2循环用变量void *Share(int threadid);//定义哲学家函数//主函数int main(){int error;//设定错误变量pthread_t threads[NUMBERS];//设置线程数for(i=0;i<5;i++)//循环设置筷子信号灯{sem_init(&chopstics[i],0,1);}sem_init(&room,0,4);//设置房间信号灯sem_init(&mutex,0,1);//设置互斥信号灯for(i=1;i<NUMBERS+1;i++)//建立十个哲学家线程{error = pthread_create(&threads[i],NULL,(void *)Share,(void *)i); if(error)//判断是否产生哲学家{printf("\nERROR: 哲学家没有被创建\n");}}for(i=1;i<NUMBERS+1;i++)//启动十个哲学家线程{pthread_join(threads[i],NULL);}}//哲学家函数void *Share(int threadid){int i = threadid;//读取哲学家编号int setnumber=1;//设置座位量sem_wait(&room);//room信号-1for(setnumber=1;setnumber<=4;setnumber++)//检测哪个位置空出来{if(youren[setnumber]==0){youren[setnumber]=i; //让哲学家去坐座位,并修改有人编号为哲学家编号printf("哲学家%d坐上了椅子%d\n",i,setnumber);sem_post(&yourenmutex);//解除有人互斥break;}}sem_wait(&chopstics[setnumber]);//拿起左边筷子信号灯printf("哲学家%d拿到左侧筷子%d\n",i,setnumber);sem_wait(&chopstics[setnumber+1]);//拿起右边筷子信号灯printf("哲学家%d拿到右侧筷子%d\n",i,setnumber+1);sem_wait(&mutex);//互斥printf("哲学家%d坐在%d椅子上吃饭\n",i,chairs[setnumber-1]);printf("dining……\n");printf("***************\n");for(j=0;j<4;j++){if(youren[j]!=0)printf("哲学家%d坐在椅子%d上\n",youren[j],chairs[j-1]);}printf("————————————\n");sem_post(&mutex);//解除互斥sleep(1);//吃十秒sem_post(&chopstics[setnumber]);//放下左边筷子信号灯sem_post(&chopstics[setnumber+1]);//放下右边筷子信号灯printf("哲学家%d吃饱了放下筷子%d和%d\n",i,setnumber,setnumber+1); sem_wait(&yourenmutex);//有人互斥youren[setnumber]=0;printf("\n哲学家%d离开了椅子%d走到一边画圈圈\n\n",i,setnumber); sem_post(&yourenmutex);//解除有人互斥sem_post(&room);//room信号灯+1}。

相关文档
最新文档