模拟PV操作同步机构,且用PV操作解决生产者——消费者问题。(转载)

模拟PV操作同步机构,且用PV操作解决生产者——消费者问题。
1、此次用到的数据结构知识如下:
typedef struct Pcb{
char name[10]; //进程名
char state[10]; //运行状态
char reason[10]; //若阻塞,其原因
int breakp; //断点保护
struct Pcb *next; //阻塞时的顺序
进程名
状态
等待原因
断点
后继进程
}Pcb,*link;

定义两个进程: link p1;//生产者进程,link c1;//消费者进程。pc程序计数器和
link ready; 就绪队列,link b_s1; s1阻塞队列,link b_s2; s2阻塞队列。
2、实验源代码:
分为四个头文件。
1、a.h头文件代码如下:`#include<string.h>

 #include<ctype.h>
 #include<malloc.h> /* malloc()等 */
 #include<limits.h> /* INT_MAX等 */
 #include<stdio.h> /* EOF(=^Z或F6),NULL */
 #include<stdlib.h> /* atoi() */
 #include<io.h> /* eof() */
 #include<math.h> /* floor(),ceil(),abs() */
 #include<process.h> /* exit() */
 #include <iostream>
 using namespace std;

 #include <time.h>
 #define BUF 10  //缓存的大小
 #define MAX 20  //最大可以输入的字符
`

2、b.h头文件代码如下:

typedef struct Pcb{ 
	char name[10];      //进程名
	char state[10];    //运行状态
	char reason[10];    //若阻塞,其原因
	int breakp;         //断点保护
	struct Pcb *next;   //阻塞时的顺序
}Pcb,*link;
int s1,s2; //信号量
link p1;//生产者进程
link c1;//消费者进程
char str[MAX]; //输入的字符串
char buffer[BUF]; //缓冲池
int len; //输入长度
int sp=0; //string的指针
int in=0; //生产者指针
int out=0; //消费者指针
char temp; //供打印的临时产品
char rec_p[MAX];//生产记录
int rp1=0;//生产记录指针
char rec_c[MAX];//消费记录
int rp2=0;//消费记录指针
link ready; //就绪队列
link b_s1; //s1阻塞队列
link b_s2; //s2阻塞队列
int pc; //程序计数器
int count; //字符计数器
int con_cnt; //消费计数器

3、c.h头文件代码如下:

void init();       //初始化
void p(int s);     //P操作
void v(int s);     //V操作
void block(int s);//阻塞函数
void wakeup(int s);//唤醒函数
void control();   //处理机调度
void processor();//处理机执行
void print();  //打印函数


void init(){ //初始化
	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; //消费计数器
}

void p(int s){
	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; //保存断点
		}
	}
}

void v(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; //保存断点
	}
}

void block(int s){//阻塞函数的定义
	link p;
	int num1=0;
	int num2=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);
}

void wakeup(int s){//唤醒函数的定义
	link p;
	link q=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() //处理器调度程序
{
	int rd;
	int num=0;

	link p=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;
		case 1: //p(s1)
			pc++;
			p(1);
			break;
		case 2: //put
			buffer[in]=rec_p[rp1]; //放到缓冲区
			printf("\t* %c字符成功入驻空缓存!\n",buffer[in]);
			rp1++; 	
			in=(in+1)%BUF;
			pc++;
			ready->breakp=pc; //保存断点
			break;
		case 3: //v(s2)
			pc++;
			printf("\t* 释放一个s2信号\n");
			v(2);
			break;
		case 4://goto01  
			printf("\t* 生产进程goto 0 操作\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)
		{
		case 0: //p(s2)
			pc++;
			p(2); 
			break;
		case 1: //get
			printf("\t* 消费者取字符!\n");
			temp=buffer[out];
			out=(out+1)%BUF;
			pc++;
			ready->breakp=pc; //保存断点
			break;
		case 2: //v(s1)
			pc++;
			printf("\t* 释放一个s1\n");
			v(1);
			break;
		case 3: //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;
		case 4: //goto0
			printf("\t* 消费进程goto 0 操作\n");
			pc=0;
			ready->breakp=pc; //保存断点
		}
}

void print(){
	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");
}

实验结果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 17
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值