模拟PV操作同步机构且用PV操作解决生产者消费者问题.docx
- 文档编号:7439403
- 上传时间:2023-05-11
- 格式:DOCX
- 页数:14
- 大小:20.85KB
模拟PV操作同步机构且用PV操作解决生产者消费者问题.docx
《模拟PV操作同步机构且用PV操作解决生产者消费者问题.docx》由会员分享,可在线阅读,更多相关《模拟PV操作同步机构且用PV操作解决生产者消费者问题.docx(14页珍藏版)》请在冰点文库上搜索。
模拟PV操作同步机构且用PV操作解决生产者消费者问题
模拟PV操作同步机构-且用PV操作解决生产者——消费者问题。
————————————————————————————————作者:
————————————————————————————————日期:
ﻩ
实验四:
同步机构实验报告
学 院:
专业班级:
姓 名:
学 号:
一、实验内容:
模拟实现用同步机构避免发生进程执行时可能出现的与时间有关的错误。
二、实验目的:
进程是程序在一个数据集合上运行的过程,进程是并发执行的,也即系统中的多个进程轮流地占用处理器运行。
我们把若干个进程都能进行访问和修改的那些变量称为公共变量。
由于进程是并发地执行的,所以,如果对进程访问公共变量不加限制,那么就会产生“与时间有关”的错误,即进程执行后所得到的结果与访问公共变量的时间有关。
为了防止这类错误,系统必须要用同步机构来控制进程对公共变量的访问。
一般说,同步机构是由若干条原语——同步原语——所组成。
本实验要求学生模拟PV操作同步机构的实现,模拟进程的并发执行,了解进程并发执行时同步机构的作用。
三、实验题目:
模拟PV操作同步机构,且用PV操作解决生产者——消费者问题。
四、此次用到的数据结构知识如下:
typedefstruct Pcb{
ﻩcharname[10]; //进程名
ﻩcharstate[10];//运行状态
ﻩcharreason[10]; //若阻塞,其原因
intbreakp;//断点保护
ﻩstruct Pcb*next; //阻塞时的顺序
进程名
状态
等待原因
断点
后继进程
}Pcb,*link;
进程控制块结构
定义两个进程:
linkp1;//生产者进程,linkc1;//消费者进程。
pc程序计数器和
linkready;就绪队列,linkb_s1;s1阻塞队列,linkb_s2;s2阻塞队列。
五、实验源代码:
分为四个头文件。
1、a.h头文件代码如下:
#include #include #include #include #include<stdio.h>/* EOF(=^Z或F6),NULL*/ #include #include #include #include #include usingnamespacestd; #include #defineBUF10//缓存的大小 #defineMAX20//最大可以输入的字符 2、b.h头文件代码如下: //数据结构的定义和全局变量 typedefstructPcb{ ﻩcharname[10]; //进程名 ﻩcharstate[10];//运行状态 charreason[10];//若阻塞,其原因 int breakp;//断点保护 ﻩstructPcb*next; //阻塞时的顺序 }Pcb,*link; int s1,s2;//信号量 linkp1;//生产者进程 link c1;//消费者进程 charstr[MAX]; //输入的字符串 charbuffer[BUF];//缓冲池 intlen;//输入长度 intsp=0;//string的指针 intin=0;//生产者指针 int out=0;//消费者指针 chartemp;//供打印的临时产品 char rec_p[MAX];//生产记录 int rp1=0;//生产记录指针 charrec_c[MAX];//消费记录 intrp2=0;//消费记录指针 linkready;//就绪队列 link b_s1; //s1阻塞队列 link b_s2;//s2阻塞队列 int pc;//程序计数器 intcount;//字符计数器 intcon_cnt;//消费计数器 3、c.h头文件代码如下: voidinit(); //初始化 void p(ints);//P操作 voidv(ints); //V操作 void block(ints);//阻塞函数 voidwakeup(ints);//唤醒函数 void control(); //处理机调度 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;//阻塞进程为NULL ﻩpc=0; ﻩcon_cnt=0;//消费计数器 } voidp(ints){ if(s==1){ //p(s1) s1--; ﻩﻩif(s1<0) block (1); //阻塞当前生产进程 ﻩelse{ ﻩﻩﻩprintf("\t*s1信号申请成功! \n"); ready->breakp=pc; //保存断点 ﻩ} ﻩ} else{//p(s2) s2--; ﻩﻩif(s2<0) ﻩblock (2);//阻塞当前消费进程 ﻩﻩelse{ ﻩprintf("\t*s2信号申请成功! \n"); ﻩﻩready->breakp=pc;//保存断点 ﻩ} ﻩ} } voidv(int s){ 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; else p=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; else ﻩﻩp=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"); } } void control() //处理器调度程序 { ﻩintrd; ﻩint num=0; linkp=ready; if(ready==NULL) //若无就绪进程,结束 return; while(p)//统计就绪进程个数 { num++; ﻩp=p->next;//最终p变为NULL } ﻩprintf("\t*就绪进程个数为: %d\n",num); ﻩ time_t t; 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"); ﻩ} else ﻩﻩstrcpy(ready->state,"Run"); ﻩpc=ready->breakp; } void processor(){ //模拟处理器指令执行 ﻩif(strcmp(ready->name,"Producer")==0)//当前进程为生产者 switch(pc) { case 0: //produce ﻩﻩprintf("\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: //put ﻩbuffer[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: //goto01 ﻩﻩprintf("\t* 生产进程goto0操作\n"); ﻩﻩpc=0; ﻩcount--;//剩余字符个数减1 ﻩﻩﻩprintf("\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; ﻩcase 1: //get ﻩprintf("\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: //consume ﻩﻩﻩprintf("\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: //goto0 ﻩﻩprintf("\t*消费进程goto 0操作\n"); ﻩﻩpc=0; ﻩready->breakp=pc;//保存断点 } } voidprint(){ int i,j; printf("————————生产者消费者模拟———————\n"); printf("*模拟过程的字符串为: \t"); ﻩprintf("%s\n",&str); ﻩ ﻩprintf("*已生产: "); for(j=0;j<=rp1;j++) ﻩprintf("%c",rec_p[j]); printf("\n* 空缓存: "); ﻩfor(j=rp2;j<=rp1;j++) ﻩprintf("%c",buffer[j]); ﻩprintf("\n*已消费: "); for(j=0;j<=rp2;j++) ﻩﻩprintf("%c",rec_c[j]); printf("\n———————进程控制块的信息————————\n"); ﻩprintf("进程名\t\t状态\t等待原因\t断点\n"); ﻩprintf("%s\t%s\t%s\t\t%d\n\n",p1->name,p1->state,p1->reason,p1->breakp); printf("%s\t%s\t%s\t\t%d\n",c1->name,c1->state,c1->reason,c1->breakp); printf("———————————————————————\n"); printf("1.继续0.退出\n"); scanf("%d",&i); if(i==0){ ﻩexit(0); } } 4、main头文件代码如下: #include"a.h" #include "b.h" #include "c.h" void main(){ printf("*生产者消费者模拟\n"); ﻩprintf("—————————\n"); ﻩprintf("*请输入字符串: \n"); scanf("%s",str);//string数组存放将要产生的字符 ﻩlen=strlen(str); ﻩcount=len; //输入字符的个数 init(); //初始化 while(con_cnt<len)//消费完所有的字符为结束 { system("cls"); //清屏操作ﻩ ﻩprintf("—————————模拟指令流程————————\n"); ﻩﻩcontrol(); //处理器调度程序 ﻩprocessor(); //模拟处理器指令执行 ﻩﻩprint(); //输出显示各个信息 ﻩ} printf("\n程序结束! \n"); } 六、运行结果截图:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 模拟 PV 操作 同步 机构 解决 生产者 消费者 问题