进程同步及死锁之欧阳光明创编
- 格式:doc
- 大小:160.02 KB
- 文档页数:7
第二章欧阳索引(2021.02.02)1. 什么是前趋图?为什么要引入前趋图?答:前趋图(Precedence Graph)是一个有向无循环图,记为DAG(Directed Acyclic Graph),用于描述进程之间执行的前后关系。
2. 画出下面四条诧句的前趋图:S1=a:=x+y;S2=b:=z+1;S3=c:=ab;S4=w:=c+1;答:其前趋图为:3. 为什么法度并发执行会产生间断性特征?法度在并发执行时,由于它们共享系统资源,以及为完成同一项任务而相互合作,致使在这些并发执行的进程之间,形成了相互制约的关系,从而也就使得进程在执行期间呈现间断性。
4. 法度并发执行时为什么会失去封闭性和可再现性?因为法度并发执行时,是多个法度共享系统中的各种资源,因而这些资源的状态是由多个法度来修改,致使法度的运行失去了封闭性。
而法度一旦失去了封闭性也会招致其再失去可再现性。
5. 在操纵系统中为什么要引入进程概念?它会产生什么样的影响?为了使法度在多道法度环境下能并发执行,并能对并发执行的法度加以控制和描述,从而在操纵系统中引入了进程概念。
影响: 使法度的并发执行得以实行。
欧阳索引创编2021.02.026. 试从静态性,并发性和自力性上比较进程和法度?a. 静态性是进程最基本的特性,可表示为由创建而产生,由调度而执行,因得不到资源而暂停执行,以及由撤消而消亡,因而进程由一定的生命期;而法度只是一组有序指令的集合,是静态实体。
b. 并发性是进程的重要特征,同时也是OS的重要特征。
引入进程的目的正是为了使其法度能和其它建立了进程的法度并发执行,而法度自己是不克不及并发执行的。
c. 自力性是指进程实体是一个能自力运行的基本单位,同时也是系统中自力获得资源和自力调度的基本单位。
而对未建立任何进程的法度,都不克不及作为一个自力的单位来运行。
7. 试说明PCB的作用?为什么说PCB是进程存在的唯一标记?a. PCB是进程实体的一部分,是操纵系统中最重要的记录型数据结构。
附件(四)之欧侯瑞魂创作深圳年夜学实验报告课程名称:把持系统实验项目名称:进程(线程)同步及死锁学院:计算机与软件学院专业:计算机科学与技术指导教师:陈说人:学号:班级:实验时间:2015/10/23实验陈说提交时间:2015/11/13教务处制二、方法、步伐:设计解决哲学家就餐问题的并发线程.假定有6个哲学家, 围着圆桌交替地进行思考和进餐;每次进餐时, 必需同时拿到左右两边的两只筷子才华进餐;进餐后, 再放下筷子思考.这是一个典范的同时需要两个资源的例子, 如果申请资源顺序不妥, 可能会引起死锁.本实验设计6个哲学家共享一个相同的线程Philosopher, 既完成线程同步, 又预防死锁发生.实验中采纳了3种预防死锁的方法(摒弃‘环路等候’条件, 摒弃‘请求和坚持’条件, 摒弃‘不剥夺’条件), 要预防死锁, 只采纳其中的任何一种方法即可. 三.实验过程及内容:(其中:提供有简短说明的法式代码.要求:法式运行正确、符合设计要求.)1.创立工程, 注意勾选Win32 Application, 点击确定2.勾选第三个选项3.创立菜单, 有Eat、About、Exit4.在进程(线程)同步及死锁.cpp中编写代码, 此时代码有“摒弃‘环路等候’条件”、“摒弃‘请求和坚持’条件”、“摒弃‘不剥夺’条件”三种代码, 当检测其中一个时须将其余两个加以注释, 一一检测其对死锁的影响.运行结果:运行前:运行后:5.在运行时可知, 在分别“摒弃‘环路等候’条件”和“摒弃‘不剥夺’条件”的代码时不会呈现死锁, 而使用“摒弃‘请求和坚持’条件”时会发生死锁, 在理论正确前提下, 此种情况说明了代码呈现毛病.⑴摒弃‘环路等候’条件R1=ThreadID;R2=(ThreadID+1)%6;if (ThreadID == 0){R1= (ThreadID+1) % 6;R2= ThreadID;}依据摒弃‘环路等候’条件, 要有至少一位哲学家与其他哲学家拿筷子顺序分歧, 则使第0位(ThreadID = 0)哲学家从右边开始拿筷子, 其他哲学家相反.⑵摒弃‘不剥夺’条件Wait(Mutex);if (ChopstickUsed[R2]){Signal(Mutex);goto ReleaseChopstick;//将左筷子放弃失落}Signal(Mutex);若分配给的哲学家拿不到右筷子, 则将他拿到的左筷子收回.⑶摒弃‘请求和坚持’条件原代码:Wait(Mutex);if((ChopstickUsed[R1])||(ChopstickUsed[R2])){Signal(Mutex);。
第一章1.设计现代OS的主要目标是什么?答:(1)有效性(2)便利性(3)可扩充性(4)开放性2.OS的作用可表示在哪几个方面?答:(1)OS作为用户与计算机硬件系统之间的接口(2)OS作为计算机系统资源的管理者(3)OS实现了对计算机资源的笼统3.为什么说OS实现了对计算机资源的笼统?答:OS首先在裸机上笼盖一层I/O设备管理软件,实现了对计算机硬件操纵的第一条理抽象;在第一层软件上再笼盖文件管理软件,实现了对硬件资源操纵的第二条理笼统。
OS 通过在计算机硬件上装置多层系统软件,增强了系统功能,隐藏了对硬件操纵的细节,由它们共同实现了对计算机资源的笼统。
4.试说明推劢多道批处理系统形成和収展的主要劢力是什么?答:主要动力来源于四个方面的社会需求与技术成长:(1)不竭提高计算机资源的利用率;(2)便利用户;(3)器件的不竭更新换代;(4)计算机体系结构的不竭成长。
5.何谓脱机I/O和联机I/O?答:脱机I/O 是指事先将装有用户法度和数据的纸带或卡片装入纸带输入机或卡片机,在外围机的控制下,把纸带或卡片上的数据或法度输欧阳语创编入到磁带上。
该方法下的输入输出由外围机控制完成,是在脱离主机的情况下进行的。
而联机I/O方法是指法度和数据的输入输出都是在主机的直接控制下进行的。
6.试说明推劢分时系统形成和収展的主要劢力是什么?答:推动分时系统形成和成长的主要动力是更好地满足用户的需要。
主要表示在:CPU 的分时使用缩短了作业的平均周转时间;人机交互能力使用户能直接控制自己的作业;主机的共享使多用户能同时使用同一台计算机,自力地处理自己的作业。
7.实现分时系统的关键问题是什么?应如何解决?答:关键问题是当用户在自己的终端上键入命令时,系统应能及时接收并及时处理该命令,在用户能接受的时延内将结果前往给用户。
解决办法:针对及时接收问题,可以在系统中设臵多路卡,使主机能同时接收用户从各个终端上输入的数据;为每个终端配臵缓冲区,暂存用户键入的命令或数据。
第二章1. 什么是前趋图?为什么要引入前趋图?答:前趋图(Precedence Graph)是一个有向无循环图,记为DAG(Directed Acyclic Graph),用于描述进程之间执行的前后关系。
2. 画出下面四条诧句的前趋图:S1=a:=x+y;S2=b:=z+1;S3=c:=ab;S4=w:=c+1;答:其前趋图为:3. 为什么法度并发执行会产生间断性特征?法度在并发执行时,由于它们共享系统资源,以及为完成同一项任务而相互合作,致使在这些并发执行的进程之间,形成了相互制约的关系,从而也就使得进程在执行期间呈现间断性。
4. 法度并发执行时为什么会失去封闭性和可再现性?因为法度并发执行时,是多个法度共享系统中的各种资源,因而这些资源的状态是由多个法度来修改,致使法度的运行失去了封闭性。
而法度一旦失去了封闭性也会招致其再失去可再现性。
欧阳道创编2021.03.065. 在操纵系统中为什么要引入进程概念?它会产生什么样的影响?为了使法度在多道法度环境下能并发执行,并能对并发执行的法度加以控制和描述,从而在操纵系统中引入了进程概念。
影响: 使法度的并发执行得以实行。
6. 试从静态性,并发性和自力性上比较进程和法度?a. 静态性是进程最基本的特性,可表示为由创建而产生,由调度而执行,因得不到资源而暂停执行,以及由撤消而消亡,因而进程由一定的生命期;而法度只是一组有序指令的集合,是静态实体。
b. 并发性是进程的重要特征,同时也是OS的重要特征。
引入进程的目的正是为了使其法度能和其它建立了进程的法度并发执行,而法度自己是不克不及并发执行的。
c. 自力性是指进程实体是一个能自力运行的基本单位,同时也是系统中自力获得资源和自力调度的基本单位。
而对未建立任何进程的法度,都不克不及作为一个自力的单位来运行。
7. 试说明PCB的作用?为什么说PCB是进程存在的唯一标记?a. PCB是进程实体的一部分,是操纵系统中最重要的记录型数据结构。
模拟死锁检测算法1.输入:“资源分配表”文件,每一行包含资源编号、进程编号两项(均用整数表示,并用空格分隔开),记录资源分配给了哪个进程。
“进程等待表”文件,每一行包含进程编号、资源编号两项(均用整数表示,并用空格分隔开),记录进程正在等待哪个资源。
下面是一个示例:资源分配表:1 12 23 3进程等待表:1 22 33 12.处理要求:程序运行时,首先提示“请输入资源分配表文件的文件名:”;再提示“请输入进程等待表文件的文件名:”。
输入两个文件名后,程序将读入两个文件中的有关数据,并按照死锁检测算法进行检测。
3.输出要求:第一行输出检测结果:有死锁或无死锁。
第二行输出进程循环等待队列,即进程编号(如果有死锁)。
4.文件名约定提交的源程序名字:resourceXXX.c或者resourceXXX.cpp (依据所用语言确定)输入文件名字:可由用户指定结果输出到resultXXX.txt中其中:XXX为账号。
5.死锁检测算法:当任一进程Pj申请一个已被其他进程占用的资源ri时,进行死锁检测。
检测算法通过反复查找进程等待表和资源分配表,来确定进程Pj对资源ri的请求是否导致形成环路,若是,便确定出现死锁。
6.测试说明:测试教师将事先准备好一组文件(格式为*. txt),从中为每个程序随机指定一至三个作为输入文件(被测试者需从键盘输入指定文件的文件名),并查看程序输出结果。
本程序包括:死锁检测算法VC++调试通过(C)copyright by Neo欢迎大家测试请问题请Email:sony006@*/#include<stdio.h>#include<iostream.h>#include<string.h>const int MAXQUEUE=100; //定义表的最大行数typedef struct node{int resource;int process;}cell;cell occupy[MAXQUEUE];int occupy_quantity;cell wait[MAXQUEUE];int wait_quantity;//初始化函数void initial(){int i;for(i=0;i<MAXQUEUE;i++){occupy[i].process=-1;occupy[i].resource=-1;wait[i].process=-1;wait[i].resource=-1;}occupy_quantity=0;wait_quantity=0;}//读数据文件int readData(){FILE *fp;char fname[20];int i;cout<<"请输入资源分配表文件的文件名:"<<endl; strcpy(fname,"10trouble1.txt");//cin>>fname;if((fp=fopen(fname,"r"))==NULL){cout<<"错误,文件打不开,请检查文件名:)"<<endl; return 0;}else{while(!feof(fp)){fscanf(fp,"%d %d",&occupy[occupy_quantity].resource, &occupy[occupy_quantity].process);occupy_quantity++;}}cout<<"请输入进程等待表文件的文件名:"<<endl; strcpy(fname,"10trouble2.txt");//cin>>fname;if((fp=fopen(fname,"r"))==NULL){cout<<"错误,文件打不开,请检查文件名:)"<<endl; return 0;}else{while(!feof(fp)){fscanf(fp,"%d %d",&wait[wait_quantity].process,&wait[wait_quantity].resource);wait_quantity++;}}//输出所读入的数据cout<<endl<<endl<<"输出所读入的数据"<<endl; cout<<"━━━━━━━━━━━━━━━━━━━━━━━"<<endl;cout<<"资源分配表"<<endl;cout<<"资源编号进程编号"<<endl;for(i=0;i<occupy_quantity;i++){cout<<" "<<occupy[i].resource<<" "<<occupy[i].pr ocess<<endl;}cout<<"───────────────────────"<<endl;cout<<"进程等待表"<<endl;cout<<"进程编号资源编号"<<endl;for(i=0;i<wait_quantity;i++){cout<<" "<<wait[i].resource<<" "<<wait[i].process <<endl;}return 1;}//检测void check(){int table[MAXQUEUE][MAXQUEUE];int table1[MAXQUEUE][MAXQUEUE];int i,j,k;int flag,t,p;int max_process;//初始化表格for(i=0;i<MAXQUEUE;i++){for(j=0;j<MAXQUEUE;j++){table[i][j]=0;table1[i][j]=0;}}//先找到进程最大编号max_process=-1;for(i=0;i<occupy_quantity;i++){if(occupy[i].process>max_process){max_process=occupy[i].process;}}for(i=0;i<wait_quantity;i++){if(wait[i].process>max_process){max_process=wait[i].process;}}for(i=0;i<wait_quantity;i++){for(j=0;j<occupy_quantity;j++){if(wait[i].resource==occupy[j].resource){ table[wait[i].process][occupy[j].process]=1;table1[wait[i].process][occupy[j].process]=1; }}}cout<<"初始等待占用表:"<<endl;for(i=0;i<max_process+1;i++){for(j=0;j<max_process+1;j++){cout<<table[i][j]<<" ";}cout<<endl;}cout<<endl;for(i=0;i<max_process+1;i++){for(j=0;j<max_process+1;j++){for(k=0;k<max_process+1;k++){table[i][j]=table[i][j]||(table[i][k]&&table[k][j]); }}}cout<<"检测后的等待占用表:"<<endl;for(i=0;i<max_process+1;i++){for(j=0;j<max_process+1;j++){cout<<table[i][j]<<" ";}cout<<endl;}flag=-1;for(i=0;i<max_process+1;i++){if(table[i][i]==1){flag=i;break;}}cout<<endl<<endl<<"检测结果"<<endl;cout<<"───────────────────"<<endl;if(flag!=-1){cout<<"存在死锁"<<endl;cout<<"进程循环等待队列:";p=flag; //存在进程循环等待队列的那一进程//进程循环等待队列中的所有进程是table表中的这一行是1的进程,只是顺序要再确定t=1;while(t){cout<<p<<" ";for(j=0;j<max_process+1;j++){if(table1[p][j]==1){if(table[j][flag]==1){p=j;break;}}}if(p==flag)t=0;}cout<<flag<<endl;}else{cout<<"不存在死锁"<<endl;}}//显示版权信息函数void version(){cout<<endl<<endl;cout<<" ┏━━━━━━━━━━━━━━━━━━━━━━━┓"<<endl;cout<<" ┃死锁检测算法┃"<<endl;cout<<" ┠───────────────────────┨"<<endl;cout<<" ┃(c)All Right Reserved Neo┃"<<endl;cout<<" ┃sony006@┃"<<endl;cout<<" ┃version 2004 build 1122 ┃"<<endl;cout<<" ┗━━━━━━━━━━━━━━━━━━━━━━━┛"<<endl; cout<<endl<<endl;}void main(){int flag;version();initial();flag=readData();if(flag)check();}。
实验四同步与互斥【实验目的和要求】1、掌握进程(线程)的同步与互斥。
2、掌握生产者消费者问题的实现方法。
3、掌握多线程编程方法。
【实验内容】实现生产者消费者问题1、有一个仓库,生产者负责生产产品,并放入仓库,消费者会从仓库中拿走产品(消费)。
2、仓库中每次只能入一个(生产者或消费者)。
3、仓库中可存放产品的数量最多10个,当仓库放满时,生产者不能再放入产品。
4、当仓库空时,消费者不能从中取出产品。
5、生产、消费速度不同。
【实验原理】1、信号量mutex提供对缓冲池访问的互斥要求并初始化为1,信号量empty和full分别用来表示空缓冲项和满缓冲项的个数,信号量empty初始化为n,信号量full 初始化为0。
2、定义如下结构及数据:定义缓冲区内的数据类型:typedef int buffer_item;缓冲区:buffer_item buffer[BUFFER_SIZE];对缓冲区操作的变量:int in,out;信号量mutex提供了对缓冲池访问的互斥要求:pthread_mutex_t mutex;信号量empty和full分别表示空缓冲顶和满缓冲顶的个数:sem_t empty,full;可以设定生产者的生产速度及消费者的消费速度:int pro_speed,con_speed;对缓冲区操作的自增函数:#define inc(k) if(k < BUFFER_SIZE) k = k+1 ;else k=03、并定义了如下实现问题的函数模块:将生产的产品放入缓冲区:int insert_item(buffer_item item)从缓冲区内移走一个产品:int remove_item(buffer_item *item)生产者进程:void *producer(void *param)消费者进程:void *consumer(void *param)生产者结构进程消费者结构进程【程序代码】//sx.c#include<stdio.h>#include<stdlib.h>#include<pthread.h>#include<semaphore.h>#include<time.h>#define inc(k) if(k<BUFFER_SIZE) k=k+1;else k=0#define BUFFER_SIZE 10//缓冲区的大小typedef int buffer_item;//定义缓冲区内的数据类型buffer_item buffer[BUFFER_SIZE];//缓冲区int in,out;//对缓冲区操作的变量pthread_mutex_t mutex;//信号量mutex提供了对缓冲池访问的互斥要求sem_t empty,full;//信号量empty和full分别表示空缓冲顶和满缓冲顶的个数int pro_speed,con_speed;//可以设定生产者的生产速度及消费者的消费速度int insert_item(buffer_item item){//将生产的产品放入缓冲区buffer[in]=item;printf("******insert缓冲池第%d号******\n",in); inc(in);}int remove_item(buffer_item *item){//从缓冲区内移走一个产品*item = buffer[out];printf("******remove缓冲池第%d号******\n",out); inc(out);}void *producer(void *param){//生产者进程buffer_item item;int num = 0;while(1){sleep(rand()%(16-pro_speed));printf("\n******第%d次生产******\n",++num); printf("******等待empty信号******\n");sem_wait(&empty);printf("******等待解锁******\n");pthread_mutex_lock(&mutex);printf("******上锁,准备生产******\n");item = rand()%1000+1;printf("******生产产品%d*******\n",item);insert_item(item);printf("*******解锁******\n");printf("******第%d次生产结束*******\n\n",num); pthread_mutex_unlock(&mutex);sem_post(&full);}}void *consumer(void *param){//消费者进程buffer_item item;int num = 0;while(1){sleep(rand()%(16-con_speed));printf("\n******第%d次消费*****\n",++num);printf("******等待full信号******\n");sem_wait(&full);printf("******等待解锁******\n");pthread_mutex_lock(&mutex);printf("******上锁,准备消费******\n");remove_item(&item);pthread_mutex_unlock(&mutex);sem_post(&empty);printf("******消费产品%d*******\n",item);printf("*******解锁******\n");printf("******第%d次消费结束*******\n\n",num); }}int main()//主函数{pthread_t tid1,tid2;pthread_attr_t attr1,attr2;srand(time(NULL));pthread_mutex_init(&mutex,NULL);//初始化sem_init(&empty,0,BUFFER_SIZE);sem_init(&full,0,0);in=0;out=0;printf("***********************\n");printf("********开始!***********\n");printf("***********************\n");printf("生产者速度(1-15):\n");scanf("%d",&pro_speed);printf("消费者速度(1-15):\n");scanf("%d",&con_speed);pthread_attr_init(&attr1);pthread_create(&tid1,&attr1,producer,NULL); pthread_attr_init(&attr2);pthread_create(&tid2,&attr2,consumer,NULL);sleep(100);printf("*******程序over*******\n");return 0;}【实验步骤】编写程序代码gedit sx.c,再对代码进行编译gcc sx.c –o sx –lpthread,编译无错误,进行运行./sx,根据提示要求进行填写生产者和消费速度,观察消费者和生产者进程。
模拟死锁检测算法1.输入:“资源分配表”文件,每一行包含资源编号、进程编号两项(均用整数表示,并用空格分隔开),记录资源分配给了哪个进程。
“进程等待表”文件,每一行包含进程编号、资源编号两项(均用整数表示,并用空格分隔开),记录进程正在等待哪个资源。
下面是一个示例:资源分配表:1 12 23 3进程等待表:1 22 33 12.处理要求:程序运行时,首先提示“请输入资源分配表文件的文件名:”;再提示“请输入进程等待表文件的文件名:”。
输入两个文件名后,程序将读入两个文件中的有关数据,并按照死锁检测算法进行检测。
3.输出要求:第一行输出检测结果:有死锁或无死锁。
第二行输出进程循环等待队列,即进程编号(如果有死锁)。
4.文件名约定提交的源程序名字:resour ceXXX.c或者resourceXXX.cpp(依据所用语言确定)输入文件名字:可由用户指定结果输出到resultXXX.txt 中其中:XXX为账号。
5.死锁检测算法:当任一进程Pj申请一个已被其他进程占用的资源ri时,进行死锁检测。
检测算法通过反复查找进程等待表和资源分配表,来确定进程Pj对资源ri的请求是否导致形成环路,若是,便确定出现死锁。
6.测试说明:测试教师将事先准备好一组文件(格式为*.txt),从中为每个程序随机指定一至三个作为输入文件(被测试者需从键盘输入指定文件的文件名),并查看程序输出结果。
本程序包括:死锁检测算法VC++调试通过(C)copyright by Neo欢迎大家测试请问题请Email:sony006@*/ #include<stdio.h>#include<iostream.h>#include<string.h>const int MAXQUEUE=100; //定义表的最大行数typedef struct node{int resource;int process;}cell;cell occupy[MAXQUEUE];int occupy_quantity;cell wait[MAXQUEUE];int wait_quantity;//初始化函数void initial(){int i;for(i=0;i<MAXQUEUE;i++){occupy[i].process=-1;occupy[i].resource=-1;wait[i].process=-1;wait[i].resource=-1;}occupy_quantity=0;wait_quantity=0;}//读数据文件int readData(){FILE *fp;char fname[20];int i;cout<<"请输入资源分配表文件的文件名:"<<endl; strcpy(fname,"10trouble1.txt");//cin>>fname;if((fp=fopen(fname,"r"))==NULL){cout<<"错误,文件打不开,请检查文件名:)"<<endl; return 0;}else{while(!feof(fp)){fscanf(fp,"%d %d",&occupy[occupy_quantity].resource,&occ upy[occupy_quantity].process);occupy_quantity++;}}cout<<"请输入进程等待表文件的文件名:"<<endl;strcpy(fname,"10trouble2.txt");//cin>>fname;if((fp=fopen(fname,"r"))==NULL){cout<<"错误,文件打不开,请检查文件名:)"<<endl;return 0;}else{while(!feof(fp)){fscanf(fp,"%d %d",&wait[wait_quantity].process,&wait[wait_ quantity].resource);wait_quantity++;}}//输出所读入的数据cout<<endl<<endl<<"输出所读入的数据"<<endl;cout<<"━━━━━━━━━━━━━━━━━━━━━━━"<<endl;cout<<"资源分配表"<<endl;cout<<"资源编号进程编号"<<endl;for(i=0;i<occupy_quantity;i++){cout<<" "<<occupy[i].resource<<" "<<occupy[i].proces s<<endl;}cout<<"───────────────────────"<<endl;cout<<"进程等待表"<<endl;cout<<"进程编号资源编号"<<endl;for(i=0;i<wait_quantity;i++){cout<<" "<<wait[i].resource<<" "<<wait[i].process<<e ndl;}return 1;}//检测void check(){int table[MAXQUEUE][MAXQUEUE]; int table1[MAXQUEUE][MAXQUEUE]; int i,j,k;int flag,t,p;int max_process;//初始化表格for(i=0;i<MAXQUEUE;i++){for(j=0;j<MAXQUEUE;j++){table[i][j]=0;table1[i][j]=0;}}//先找到进程最大编号max_process=-1;for(i=0;i<occupy_quantity;i++){if(occupy[i].process>max_process){ max_process=occupy[i].process;}}for(i=0;i<wait_quantity;i++){if(wait[i].process>max_process){max_process=wait[i].process;}}for(i=0;i<wait_quantity;i++){for(j=0;j<occupy_quantity;j++){if(wait[i].resource==occupy[j].resource){table[wait[i].process][occupy[j].process]=1; table1[wait[i].process][occupy[j].process]=1; }}}cout<<"初始等待占用表:"<<endl;for(i=0;i<max_process+1;i++){for(j=0;j<max_process+1;j++){cout<<table[i][j]<<" ";}cout<<endl;}cout<<endl;for(i=0;i<max_process+1;i++){for(j=0;j<max_process+1;j++){for(k=0;k<max_process+1;k++){table[i][j]=table[i][j]||(table[i][k]&&table[k][j]); }}}cout<<"检测后的等待占用表:"<<endl;for(i=0;i<max_process+1;i++){for(j=0;j<max_process+1;j++){cout<<table[i][j]<<" ";}cout<<endl;}flag=-1;for(i=0;i<max_process+1;i++){if(table[i][i]==1){flag=i;break;}}cout<<endl<<endl<<"检测结果"<<endl;cout<<"───────────────────"<<end l;if(flag!=-1){cout<<"存在死锁"<<endl;cout<<"进程循环等待队列:";p=flag; //存在进程循环等待队列的那一进程//进程循环等待队列中的所有进程是table表中的这一行是1的进程,只是顺序要再确定t=1;while(t){cout<<p<<" ";for(j=0;j<max_process+1;j++){if(table1[p][j]==1){if(table[j][flag]==1){p=j;break;}}}if(p==flag)t=0;}cout<<flag<<endl;}else{cout<<"不存在死锁"<<endl;}}//显示版权信息函数void version(){cout<<endl<<endl;cout<<" ┏━━━━━━━━━━━━━━━━━━━━━━━┓"<<endl;cout<<" ┃死锁检测算法┃"<<en dl;cout<<" ┠───────────────────────┨"<<endl;cout<<" ┃(c)All Right Reserved Neo ┃" <<endl;cout<<" ┃sony006@┃"<<endl;cout<<" ┃version 2004 build 1122┃"<<endl;cout<<" ┗━━━━━━━━━━━━━━━━━━━━━━━┛"<<endl;cout<<endl<<endl;}void main(){int flag;version();initial();flag=readData();if(flag)check();}。
附件(四)
欧阳光明(2021.03.07)
深圳大学实验报告课程名称:操作系统
实验项目名称:进程(线程)同步及死锁学院:计算机与软件学院
专业:计算机科学与技术
指导教师:
报告人:学号:班级:
实验时间:2015/10/23
实验报告提交时间:2015/11/13
教务处制
二、方法、步骤:
设计解决哲学家就餐问题的并发线程。
假定有6个哲学家,围着圆桌交替地进行思考和进餐;每次进餐时,必须同时拿到左右两边的两只筷子才能进餐;进餐后,再放下筷子思考。
这是一个典型的同时需要两个资源的例子,如果申请资源顺序不当,可能会引起死锁。
本实验设计6个哲学家共享一个相同的线程Philosopher,既完成线程同步,又预防死锁发生。
实验中采用了3种预防死锁的方法(摒弃‘环路等待’条件,摒弃‘请求和保持’条件,摒弃‘不剥夺’条件),要预防死锁,只采用其中的任何一种方法即可。
三.实验过程及内容:(其中:提供有简短说明的程序代码。
要求:程序运行正确、符合设计要求。
)
1.创建工程,注意勾选Win32 Application,点击确定
2.勾选第三个选项
3.创建菜单,有Eat、About、Exit
4.在进程(线程)同步及死锁.cpp中编写代码,此时代码有“摒弃‘环路等待’条件”、“摒弃‘请求和保持’条件”、“摒弃‘不剥夺’条件”三种代码,当检测其中一个时须将其余两个加以注释,一一检测其对死锁的影响。
运行结果:
运行前:
运行后:
5.在运行时可知,在分别“摒弃‘环路等待’条件”和“摒弃‘不剥夺’条件”的代码时不会出现死锁,而使用“摒弃‘请求和保持’条件”时会产生死锁,在理论正确前提下,此种情况说明了代码出现错误。
6.代码解释及修改⑴摒弃‘环路等待’条件
R1=ThreadID;
R2=(ThreadID+1)%6;
if (ThreadID == 0)
{
R1= (ThreadID+1) % 6;
R2= ThreadID;
}
依据摒弃‘环路等待’条件,要有至少一位哲学家与其他哲学家拿筷子顺序不同,则使第0位(ThreadID = 0)哲学家从右边开始拿筷子,其他哲学家相反。
⑵摒弃‘不剥夺’条件
Wait(Mutex);
if (ChopstickUsed[R2])
{
Signal(Mutex);
goto ReleaseChopstick;//将左筷子放弃掉
}
Signal(Mutex);
若分配给的哲学家拿不到右筷子,则将他拿到的左筷子收回。
⑶摒弃‘请求和保持’条件
原代码:
Wait(Mutex);
if((ChopstickUsed[R1])||(ChopstickUsed[R2]))
{
Signal(Mutex);
goto LoopAgain;//思考。