进程同步和通信 -生产者和消费者问题模拟

时间:2022-08-03 20:22:34
程序说明:这是我自己修改后的操作系统实验题目(这里有许多创新之处,至少对我而言)。
缓冲区可以容纳8个数据;因为缓冲区是有限的,因此当其满了时生产者进程应该等待;当消费者取走一个数据后,应唤醒正在等待的生产者进程;
当缓冲区空时,消费者进程应该等待;当生产者向缓冲区放入了一个数据时,应唤醒正在等待的消费者进程。这就是生产者和消费者之间的同步。
每次写入和读出数据时,都将读和写指针加一。当指针到达缓冲区尾,重新将指针退回起点;
为简单起见,每次产生的数据为0-99的整数,从0开始,顺序递增;
两个进程的调度是通过运行者使用键盘来实现的。 
启动程序后,如果使用‘p’键则运行一次生产者进程;
使用‘c’键则运行一次消费者进程;
使用‘e’键则退出程序;
通过屏幕可以观察到两个进程的状态和缓冲区变化的情况。 
程序源代码如下:
#include <stdio.h>
#include<stdlib.h>
#define PIPESIZE 8
#define PRODUCER 0
#define CONSUMER 1
#define PIPE_PRODUCER_SIZE 40

struct pcb
{
    char *name;
    int statu;
    int time;
    int flag; //标识1为有产品,0为没有产品
}; // 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][2];
int pipe_produce[PIPE_PRODUCER_SIZE]; //生产者队列
int i_prodece=0;
int i_consume=0;
int sum=0;//产品总数
struct pipetype pipetb;
struct pcb process[2];
int runp(int out,struct pcb p[],int pipe[][2],struct pipetype *tb,int t) //run producer
{
    if(i_consume>0) //把产品分发给等待中的消费者
    {
        printf("\n ****************************");
        printf("\n 产品 %d 已分发给待消费者了. ",out);
        printf("\n 待消费的产品数为:%d",--i_consume);
        printf("\n ****************************\n");
        return 0;
    }
    printf("\n PRODUCER Running !\tProduct %d ",out);
    if((tb->writeptr==tb->readptr)&&(pipe[(tb->writeptr+1)%8][1]==1))
    {
//pipe[8]已经填满,把产品存储在生产者队列中
        pipe_produce[i_prodece]=out;
        i_prodece++;
        sum++;
        return 0;
    }
    pipe[tb->writeptr][0]=out; //out为产品标识
    pipe[tb->writeptr][1]=1; //标识有产品
    tb->writeptr++;
    tb->writeptr=(tb->writeptr%8);
    sum++;
    return 0;
}
int runc(struct pcb p[],int pipe[][2],struct pipetype *tb,int t) //run consumer
{
    if(sum<=0) //消费者等待
    {
        i_consume++;
        printf("\n ****************************");
        printf("\n 没有产品了,消费者进入队列. ");
        printf("\n 待消费的产品数为:%d",i_consume);
        printf("\n ****************************\n");
        sum--;
        return 0;
    }
    if(sum>PIPESIZE) //产品总数大于8
    {
        printf("\n CONSUMER Running !\tConsumer %d ",pipe_produce[0]);
        pipe[tb->readptr][0]=pipe_produce[0];
        pipe[tb->readptr][1]=1;
        tb->readptr++;
        tb->readptr=(tb->readptr%8);
        sum--;
        if(sum>8)
            for(int i=0; i<i_prodece; i++)
                pipe_produce[i]=pipe_produce[i+1];
        i_prodece--;
        return 0;
    }
    if(sum==PIPESIZE) //重新定位开始生产的指针
        tb->writeptr=tb->readptr;
    printf("\n CONSUMER Running !\tConsumer %d ",pipe[tb->readptr][0]);
    pipe[tb->readptr][1]=0; //已经消费掉
    tb->readptr++;
    tb->readptr=(tb->readptr%8);
    sum--;
    return 0;
}
void prn(struct pcb p[],int pipe[][2],struct pipetype tb)
{
    int i;
    printf("\n ");
    for(i=0; i<PIPESIZE; i++) printf("------ ");
    printf("\n |");
    for(i=0; i<PIPESIZE; i++)
        if(pipe[i][1]==1) printf(" %2d |",pipe[i][0]);
        else printf(" |");
    printf("\n ");
    for(i=0; i<PIPESIZE; i++) printf("------ ");
    printf("\n");
    printf("\n writeptr = %d,\treadptr = %d ",tb.writeptr,tb.readptr);
    if(sum>PIPESIZE)
    {
        printf("\n 生产者缓冲区: ");
        for(i=0; i<i_prodece; i++)
            printf("%2d |",pipe_produce[i]);
        printf("\n");
    }
}
int main()
{
    int output,ret,i;
    char in[2];
    pipetb.type = 'c';
    pipetb.writeptr = 0;
    pipetb.readptr = 0;
    pipetb.pointp = pipetb.pointc = NULL;
    process[PRODUCER].name = "Producer\0";
    process[CONSUMER].name = "Consumer\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++)
    {
        printf("\n +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n ");
        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')
        {
            runp(output,process,pipe,&pipetb,PRODUCER);
            output = (output++)%100;
        }
        if(in[0]=='c')
            runc(process,pipe,&pipetb,CONSUMER); //消费一个产品
        prn(process,pipe,pipetb);
        in[0]='N';
    }
    return 0;
}