实验四:同步机构实验报告学院:专业班级:姓名:学号:一、实验内容:模拟实现用同步机构避免发生进程执行时可能出现的与时间有关的错误。二、实验目的:进程是程序在一个数据集合上运行的过程,进程是并发执行的,也即系统中的多个进程轮流地占用处理器运行。我们把若干个进程都能进行访问和修改的那些变量称为公共变量。由于进程是并发地执行的,所以,如果对进程访问公共变量不加限制,那么就会产生“与时间有关”的错误,即进程执行后所得到的结果与访问公共变量的时间有关。为了防止这类错误,系统必须要用同步机构来控制进程对公共变量的访问。一般说,同步机构是由若干条原语——同步原语——所组成。本实验要求学生模拟PV操作同步机构的实现,模拟进程的并发执行,了解进程并发执行时同步机构的作用。三、实验题目:模拟PV操作同步机构,且用PV操作解决生产者——消费者问题。四、此次用到的数据结构知识如下:typedefstructPcb{charname[10];//进程名charstate[10];//运行状态charreason[10];//若阻塞,其原因intbreakp;//断点保护structPcb*next;//阻塞时的顺序}Pcb,*link;进程名状态等待原因断点后继进程进程控制块结构定义两个进程:linkp1;//生产者进程,linkc1;//消费者进程。pc程序计数器和linkready;就绪队列,linkb_s1;s1阻塞队列,linkb_s2;s2阻塞队列。五、实验源代码:分为四个头文件。1、a.h头文件代码如下:#includestring.h#includectype.h#includemalloc.h/*malloc()等*/#includelimits.h/*INT_MAX等*/#includestdio.h/*EOF(=^Z或F6),NULL*/#includestdlib.h/*atoi()*/#includeio.h/*eof()*/#includemath.h/*floor(),ceil(),abs()*/#includeprocess.h/*exit()*/#includeiostreamusingnamespacestd;#includetime.h#defineBUF10//缓存的大小#defineMAX20//最大可以输入的字符2、b.h头文件代码如下://数据结构的定义和全局变量typedefstructPcb{charname[10];//进程名charstate[10];//运行状态charreason[10];//若阻塞,其原因intbreakp;//断点保护structPcb*next;//阻塞时的顺序}Pcb,*link;ints1,s2;//信号量linkp1;//生产者进程linkc1;//消费者进程charstr[MAX];//输入的字符串charbuffer[BUF];//缓冲池intlen;//输入长度intsp=0;//string的指针intin=0;//生产者指针intout=0;//消费者指针chartemp;//供打印的临时产品charrec_p[MAX];//生产记录intrp1=0;//生产记录指针charrec_c[MAX];//消费记录intrp2=0;//消费记录指针linkready;//就绪队列linkb_s1;//s1阻塞队列linkb_s2;//s2阻塞队列intpc;//程序计数器intcount;//字符计数器intcon_cnt;//消费计数器3、c.h头文件代码如下:voidinit();//初始化voidp(ints);//P操作voidv(ints);//V操作voidblock(ints);//阻塞函数voidwakeup(ints);//唤醒函数voidcontrol();//处理机调度voidprocessor();//处理机执行voidprint();//打印函数voidinit(){//初始化s1=BUF;s2=0;p1=(link)malloc(sizeof(Pcb));//建立新的结点,并初始化为生产者strcpy(p1-name,Producer);strcpy(p1-state,Ready);strcpy(p1-reason,Null);p1-breakp=0;p1-next=NULL;c1=(link)malloc(sizeof(Pcb));//建立新的结点,并初始化为消费者strcpy(c1-name,Consumer);strcpy(c1-state,Ready);strcpy(c1-reason,Null);c1-breakp=0;c1-next=NULL;ready=p1;ready-next=c1;//初始化为生产进程在前,消费进程在后c1-next=NULL;b_s1=NULL;b_s2=NULL;//阻塞进程为NULLpc=0;con_cnt=0;//消费计数器}voidp(ints){if(s==1){//p(s1)s1--;if(s10)block(1);//阻塞当前生产进程else{printf(\t*s1信号申请成功!\n);ready-breakp=pc;//保存断点}}else{//p(s2)s2--;if(s20)block(2);//阻塞当前消费进程else{printf(\t*s2信号申请成功!\n);ready-breakp=pc;//保存断点}}}voidv(ints){if(s==1){//v(s1)s1++;if(s1=0)wakeup(1);//唤醒生产进程ready-breakp=pc;//保存断点}else{//v(s2)s2++;if(s2=0)wakeup(2);//唤醒消费进程ready-breakp=pc;//保存断点}}voidblock(ints){//阻塞函数的定义linkp;intnum1=0;intnum2=0;if(s==1){//生产进程strcpy(p1-state,Block);//改变状态strcpy(p1-reason,S1);//说明原因p=b_s1;while(p){num1++;p=p-next;//p的值为NULL,表示队尾}if(!b_s1)b_s1=p1;elsep=p1;p1-next=NULL;printf(\t*p1生产进程阻塞了!\n);ready-breakp=pc;//保存断点ready=ready-next;//在就绪队列中去掉,指向下一个num1++;}else{//消费进程strcpy(c1-state,Block);strcpy(c1-reason,S2);p=b_s2;while(p){num2++;p=p-next;//p的值为NULL,表示队尾}if(!b_s2)b_s2=c1;elsep=c1;ready-breakp=pc;//保存断点ready=ready-next;//在就绪队列中去掉,指向下一个c1-next=NULL;printf(\t*c1消费进程阻塞了!\n);num2++;}printf(\t*阻塞的生产进程个数为:%d\n,num1);printf(\t*阻塞的消费进程个数为:%d\n,num2);}voidwakeup(ints){//唤醒函数的定义linkp;linkq=ready;if(s==1){//唤醒b_s1队首进程,生产进程队列p=b_s1;b_s1=b_s1-next;//阻塞指针指向下一个阻塞进程strcpy(p-state,Ready);strcpy(p-reason,Null);while(q)//插入就绪队列q=q-next;q=p;p-next=NULL;printf(\t*p1生产进程唤醒了!\n);}else{//唤醒b_s2队首进程,消费进程队列p=b_s2;b_s2=b_s2-next;//阻塞指针指向下一个阻塞进程strcpy(p-state,Ready);strcpy(p-reason,Null);while(q-next)//插入就绪队列q=q-next;q-next=p;p-next=NULL;printf(\t*c1消费进程唤醒了!\n);}}voidcontrol()//处理器调度程序{intrd;intnum=0;linkp=ready;if(ready==NULL)//若无就绪进程,结束return;while(p)//统计就绪进程个数{num++;p=p-next;//最终p变为NULL}printf(\t*就绪进程个数为:%d\n,num);time_tt;srand((unsigned)time(&t));rd=rand()%num;//随机函数产生随机数if(rd==1){p=ready;ready=ready-next;ready-next=p;p-next=NULL;strcpy(ready-state,Run);strcpy(ready-next-state,Ready);}elsestrcpy(ready-state,Run);pc=ready-breakp;}voidprocessor(){//模拟处理器指令执行if(strcmp(ready-name,Producer)==0)//当前进程为生产者switch(pc){case0://produceprintf(\t*生产者生产了字符%c\n,str[sp]);rec_p[rp1]=str[sp];//添加到生产记录sp=(sp+1)%len;pc++;ready-breakp=pc;//保存断点break;case1://p(s1)pc++;p(1);break;case2://putbuffer[in]=rec_p[rp1];//放到缓冲区printf(\t*%c字符成功入驻空缓存!\n,buffer[in]);rp1++;in=(in+1)%BUF;pc++;ready-breakp=pc;//保存断点break;case3://v(s2)pc++;printf(\t*释放一个s2信号\n);v(2);break;case4://goto01printf(\t*生产进程goto0操作\n);pc=0;count--;//剩余字符个数减1printf(\t*剩余字符count=%d个\n,count);ready-breakp=pc;//保存断点if(count=0){//生产结束printf(\t*生产者结束生产!\n);strcpy(p1-state,Stop);strcpy(p1-reason,Null);ready-breakp=-1;ready=ready-next;//在就绪队列中去掉}}else//当前进程为消费者switch(pc){case0://p(s2)pc++;p(2);break;case1://getprintf(\t*消费者取字符!\n);temp=buffer[out];out=(out+1)%BUF;pc++;ready-breakp=pc;//保存断点break;case2://v(s1)pc++;printf(\t*释放一个s1\n);v(1);break;case3://consumeprintf(\t*消费了字符%c\n,temp);rec_c[rp2]=temp;//添加到消费记录rp2++;con_cnt++;if(con_cnt=len){strcpy(c1-state,Stop);//完成态c1-breakp=-1;return;}pc++;ready-breakp=pc;//保存断点break;case4://goto0printf(\t*消费进程goto0操作\n);pc=0;ready-breakp=pc;//保存断点}}voidprint()