操作系统进程的同步与互斥实验

本文介绍了一个C语言编写的生产者消费者模型程序,通过循环缓冲区解决资源同步问题。程序模拟两个进程,生产者生成0-99的整数存入缓冲区,消费者取出并使用。当缓冲区满或空时,进程会进入等待状态,直到被唤醒。文章详细展示了程序的源代码、数据流图以及解决问题的过程,强调了同步和唤醒操作的重要性。
摘要由CSDN通过智能技术生成

提示:虚心求教

文章目录

  • 1.实验方法
  • 2.数据流图
  • 3.实验源代码
  • 4.运行截图
  • 5.问题及解决办法
  • 6.实验总结


1.实验方法

(1)程序说明:

本程序是模拟两个进程,生产者 (producer)和消费者(Consumer)工作。

生产者每次产生一个数据,送入缓冲区中。消费者每次从缓冲区中取走一个数据。缓冲区可以容纳 8个数据。因为缓冲区是有限的,因此当其满了时生产者进程应该等待,而空时,消费者进程应该等待 当生产者向缓冲区放入了一个数据,应唤醒正在等待的消费者进程,同样,当消费者取走一个数据后,应唤醒正在等待的生产者进程。就是生产者和消费者之间的同步。每次写入和读出数据时,都将读和写指针加一。当读写指针同样时,又一起退回起点。当写指针指向最后时,生产者就等待。当读指针为零时,再次要读取的消费者也应该等待。

为简单起见,每次产生的数据为 0-99 的整数,从0开始,顺序递增。两个进程的调度是通过运行者使用键盘来实现的。

(2)使用说明:

启动程序后,如果使用’p‘键则进行一次生产者进程,’c‘键则运行一次消费者进程。屏幕可观察俩个进程的状态和缓冲区变化的情况。

  1. 个人见解:

完美解决无法循环利用缓冲区问题:按生产序号顺序消费,生产多于管道个数的产品放进仓库(阻塞状态),当管道有空时唤醒仓库里的产品放入管道(队列——先进先出),按生产序号顺序消费,当无产品时不能消费。

2.数据流图

 

 

 

3.实验源代码

/***************************************************************/
/*     PROGRAM NAME:       PRODUCER_CONSUMER    */
/*    This program simulates two processes, producer which        */
/* continues  to produce message and  put it into a buffer         */
/* [implemented by PIPE], and consumer which continues to get      */
/* message from the buffer and use it.                            */
/*    The program also demonstrates the synchronism between      */
/* processes and uses of PIPE.                                 */
/***************************************************************/
#include <stdlib.h>
#define PIPESIZE 8
#define PRODUCER 0
#define CONSUMER 1
#define RUN      0    /* statu of process */
#define WAIT     1    /* statu of process */
#define READY    2    /* statu of process */
#define NORMAL   0
#define SLEEP    1
#define AWAKE    2

#include <stdio.h>
  	struct pcb { 
	  	char *name;
       	int  statu;
    	int  time;   
		};  /* times of execution */
  	struct pipetype { 
	  	char type;
        int  writeptr;
        int  readptr;
        struct pcb *pointp;     /* write wait point */
        struct pcb *pointc;  	/* read wait point  */
		}; 
  	int pipe[PIPESIZE];
  	struct pipetype pipetb;
  	struct pcb process[2];
  	int count=0; //定义产品初始量 
	main()
{ 
	int output,ret,i;
  	char in[2];
  	int runp(),runc(),prn();
	pipetb.type = 'c'; pipetb.writeptr = 0; pipetb.readptr = 0;
  	pipetb.pointp = pipetb.pointc = NULL;
  	process[PRODUCER].name = "Producer\0";
  	process[CONSUMER].name = "Consumer\0";
  	process[PRODUCER].statu = process[CONSUMER].statu = READY;
  	process[PRODUCER].time = process[CONSUMER].time = 0;
  	output = 0;
  	printf("Now starting the program!\n");
  	printf("Press 'p' to run PRODUCER, press 'c' to run CONSUMER.\n");
  	printf("Press 'e' to exit from the program.\n");
  	for(i=0;i<1000;i++)  { 
	  	in[0]='N';
    	while(in[0]=='N') { 
			scanf("%s",in);
        if(in[0]!='e'&&in[0]!='p'&&in[0]!='c') 
			in[0]='N';
		}
    	if(in[0]=='e') { 
			printf("Program completed!\n"); 
			exit(0); 
		}
    	if(in[0]=='p'&&process[PRODUCER].statu==READY) {
     		//if(count<8)    //有空闲位置,产品量加一 
     			output = (output+1)% 100 ;
        	if((ret=runp(output,process,pipe,&pipetb,PRODUCER))==SLEEP)
           		pipetb.pointp = &process[PRODUCER];
        	if(ret==AWAKE) {
           		(pipetb.pointc)->statu=READY; pipetb.pointc=NULL;
           		runc(process,pipe,&pipetb,CONSUMER); //先前此处注释故错误3 
           		process[CONSUMER].statu=READY;
		   	}
      	}
     	if(in[0]=='c'&&process[CONSUMER].statu==READY) {
        	if((ret=runc(process,pipe,&pipetb,CONSUMER))==SLEEP){
           		pipetb.pointc = &process[CONSUMER];
			}
        	if(ret==AWAKE) {
           		(pipetb.pointp)->statu=READY; pipetb.pointp=NULL;
           		runp(output,process,pipe,&pipetb,PRODUCER);//先前此处注释故错误2
           		//process[PRODUCER].statu=READY;
		    }
      	}
     	if(in[0]=='p'&&process[PRODUCER].statu==WAIT)
        	printf("PRODUCER is waiting, can't be scheduled.\n");
     	if(in[0]=='c'&&process[CONSUMER].statu==WAIT)
        	printf("CONSUMER is waiting, can't be scheduled.\n");
     	prn(process,pipe,pipetb); in[0]='N'; }
 }
 int runp(out,p,pipe,tb,t)  /* run producer */
 int out,pipe[],t;
 struct pcb p[];
 struct pipetype *tb;
 { 
 	p[t].statu = RUN; 
	printf("run PRODUCER. product %d     ",out);
   	if(count>=8) { 
	   	p[t].statu=WAIT; 
		return(SLEEP); 
	}
   	pipe[tb->writeptr]=out;
   	count++;
   	tb->writeptr++;
   	tb->writeptr%=8;  //保证输入指针处于队列之中 
	p[t].time++;
   	p[t].statu=READY; 
	if((tb->pointc)!=NULL) 
		return(AWAKE);
   	return(NORMAL);
 }
 int runc(p,pipe,tb,t)      /* run consumer */
 int pipe[],t;
 struct pcb p[];
 struct pipetype *tb;
 { 
 	int c;
   	p[t].statu = RUN; 
	printf("run CONSUMER. ");
   	if(count<=0) { 
	   	p[t].statu=WAIT; 
		return(SLEEP);
	}
   	c = pipe[tb->readptr];
   	pipe[tb->readptr]=0; 	//取出,赋零值 
   	count--;				//产品量减一 
   	tb->readptr++;
   	tb->readptr%=8;         //保证输出指针处于队列之中 
   	printf(" use %d      ",c);
   	if(tb->readptr==tb->writeptr)    //队列为空,指针回到队头 
	   	tb->readptr=tb->writeptr=0;
   	p[t].time++; 
	p[t].statu=READY;
   	if(tb->pointp!=NULL)
   	//if((tb->readptr)==0&&(tb->pointp)!=NULL) 
   		return(AWAKE);
   	return(NORMAL);
 }
 int prn(p,pipe,tb)
 int pipe[];
 struct pipetype tb;
 struct pcb p[];
 { 
 	int i,j;
   	printf("\n         "); 
	for(i=0;i<PIPESIZE;i++) 
		printf("------ ");
   	printf("\n        |");
   	for(i=0;i<PIPESIZE;i++)
      	if(pipe[i])
	  		printf("  %2d  |",pipe[i]);
        else 
			printf("      |");
   	printf("\n         "); 
   	for(i=0;i<PIPESIZE;i++) 
   		printf("------ ");
   	printf("\nwriteptr = %d, readptr = %d,  ",tb.writeptr,tb.readptr);
   	if(p[PRODUCER].statu==WAIT) 
	   	printf("PRODUCER wait ");
    else 
		printf("PRODUCER ready ");
   	if(p[CONSUMER].statu==WAIT) 
   		printf("CONSUMER wait ");
    else 
		printf("CONSUMER ready ");
   	printf("\n");
 }

4.运行截图

 

 

 

 

5.问题及解决办法

Question1

我一开始实验九个产品  一个管道只能放八个 所以九号产品在仓库(阻塞状态)。

当消费后管道有空时九号产品就可以唤醒放进第一个空间,这时九号产品未被更改生产序号+1入队。

Answer1:

更改生产者和消费者的就绪态代码:

更改后如下图,为解决question1则有question2:

Question2

我一开始实验九个产品  一个管道只能放八个 所以九号产品在仓库(阻塞状态),writeptr与readptr指针在管道满队时未更改为0。

当消费后管道有空时九号产品就可以唤醒放进第一个空间,这时九号产品未被唤醒(就绪状态)入队,此时的writeptr与readptr指针分别未指向1。

 

Answer2

更改消费者的就绪状态代码:

更改后,可如下图满足初始需求:

 

Question3

当第八号产品被消费后管道全空时,再消费产品就需等待生产,再生产时为第九号产品被等待的消费者消费,此时管道应仍为空,再生产第十号产品才被放入管道,九号产品在管道里面未被等待的消费者消费,故消费者阻塞状态未唤醒需修改代码。

Answer3

更改消费者的就绪状态代码:

更改后,可如下图满足初始需求:

 

6.实验总结

(1)运用循环队列(先进先出),多线程编程,wait()函数,类中的index、in、out。

(2)使用的数据结构:

进程控制块:进程名、进程状态、执行次数。

缓冲区:一个整数数组。

缓冲区说明:类型、读指针、写指针、读等待指针和写等待指针。

(3)生产者和消费者的阻塞状态的唤醒运行容易忘记!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值