操作系统-生产者消费者问题-代码

参考自
https://wenku.baidu.com/view/ff323be3b5daa58da0116c175f0e7cd18425188c.html

#include<iostream>
#include<string>
#include<cstdlib>
#include <queue>
#include<algorithm>
#include<stdio.h>
#include<malloc.h> 
#include<string.h>
using namespace std;
//pcb结构 
struct PCB{
    char name[10];//进程名 
    int id;//进程标号 1为生产者,2为消费者 
};
//链队列
typedef struct QNode{
	PCB data;
	struct QNode *next;
}QNode,*QueuePtr;
typedef struct{
    QueuePtr front;//头指针
    QueuePtr rear;//尾指针
}LinkQueue;
//初始化链队列
void QueueInit(LinkQueue &Q){
    Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));
    Q.front->next=NULL;
}
//入队
void EnQueue(LinkQueue &Q,QueuePtr p){
    p->next=NULL;
    Q.rear->next=p;
    Q.rear=p;
}
//出队,返回的是QueuePtr类型的元素。 
QueuePtr DeQueue(LinkQueue &Q){
    QueuePtr p=Q.front->next;
    Q.front->next=p->next;
    if(Q.rear==p){
        Q.rear=Q.front;
	}
    return p;
}
//出队
/*
void outqueue(LinkQueue &Q){
    QueuePtr p=Q.front->next;
    Q.front->next=p->next;
	if(Q.rear==p)
    	Q.rear=Q.front;
    delete p;
}
*/ 
//创建进程进入初始队列
void processproc(LinkQueue &Q){
    int processNum=0;
    cout<<"请输入进程个数:";
    cin>>processNum;
    for(int i=0;i<processNum;i++){
        cout<<"输入第"<<i+1<<"个进程的种类,生产者输入1,消费者输入2"<<endl;
        struct PCB pcb;
		cin>>pcb.id;
        cout<<"输入进程名";
        cin>>pcb.name;
        QueuePtr p=(QueuePtr)malloc(sizeof(QNode));
        p->data.id=pcb.id;
		strcpy(p->data.name,pcb.name);
        EnQueue(Q,p);
    }
}
//判断队列是否为空
bool HasElement(LinkQueue Q){
    if(Q.front==Q.rear)
        return 0;
    else
        return 1;
}
//生产者
int ProduceRun(int &full,int BufferSize){
    if(full<BufferSize){//即还有空间
        full++;
        return 1;
    }
    return 0;
}
//消费者
int ConsumeRun(int &full,int BufferSize){
    if(full>0){
        full--;
        return 1;
    }
    return 0;
}
//打印队列
void DisPlay(LinkQueue Q){
    QueuePtr p=Q.front;
    while(p->next){
        cout<<"进程"<<p->next->data.name<<endl;
        p=p->next;
    }
}
//打印over队列 
void DisPlay1(LinkQueue Q){
	QueuePtr p=Q.front;
    while(p->next){
        cout<<p->next->data.id<<" ";
        p=p->next;
    }
    cout<<endl;
}
//队列元素个数 
int queuenum(LinkQueue Q){
	int count=0;
	QueuePtr p;
	p=Q.front->next;
	while(p!=NULL){
		count++;
		p=p->next;
	}
	return count;
}
int main(){
    int BufferSize;//缓冲区大小
    cout<<"设置缓冲区大小:";
    cin>>BufferSize;
    int full=0;//当前缓冲区中进程数目
    int temp=1;
    LinkQueue over;//结束链表 
    QueueInit(over);//链表初始化 
    LinkQueue ReadyQueue;//就绪队列 
    LinkQueue ProducerWaitQueue;//生产者等待队列 
    LinkQueue ConsumerWaitQueue;//消费者等待队列 
    QueueInit(ReadyQueue);
    QueueInit(ProducerWaitQueue);
    QueueInit(ConsumerWaitQueue);
    processproc(ReadyQueue);//进程初始化
	bool element=queuenum(ReadyQueue);//判断就绪队列是否为空
    while(element){
    	cout<<"进程"<<ReadyQueue.front->next->data.name<<"申请运行,它是一个";
    	if(ReadyQueue.front->next->data.id==1){//生产者进程
            cout<<"生产者"<<endl;
            if(ProduceRun(full,BufferSize)==1){//即还有空间可存入
                cout<<"进程"<<ReadyQueue.front->next->data.name<<"执行完毕"<<endl;
                EnQueue(over,DeQueue(ReadyQueue)); 
                //outqueue(ReadyQueue);
				if(queuenum(ConsumerWaitQueue)!=0){//消费者等待队列仍有消费者时候。要唤醒消费者
					EnQueue(ReadyQueue,DeQueue(ConsumerWaitQueue));
                    //outqueue(ConsumerWaitQueue);
				}
            }
            else if(ProduceRun(full,BufferSize)==0){//如果没空间,则进入生产者等待队列
				EnQueue(ProducerWaitQueue,DeQueue(ReadyQueue));
                //outqueue(ReadyQueue);
            	if(queuenum(ConsumerWaitQueue)!=0){//消费者等待队列中有,则入到就绪队列,即唤醒消费者。
               		EnQueue(ReadyQueue,DeQueue(ConsumerWaitQueue));
                    //outqueue(ConsumerWaitQueue);
                }
            }
        }
        else{//消费者
            cout<<"消费者"<<endl;
            if(ConsumeRun(full,BufferSize)==1){//即buffer中有生产者进程。full-1,消费掉一个生产者,并进入over链表
                EnQueue(over,DeQueue(ReadyQueue));
                //outqueue(ReadyQueue);
            }
            else if(ConsumeRun(full,BufferSize)==0){//buffer中无进程,进入消费者等待,同时唤醒生产者
				EnQueue(ConsumerWaitQueue,DeQueue(ReadyQueue));//加入消费者等待
                if(queuenum(ProducerWaitQueue)!=0){//生产者等待队列中有数据,则加入到就绪队列,即唤醒生产者。
                    EnQueue(ReadyQueue,DeQueue(ProducerWaitQueue));
                    cout<<"生产者等待队列数量"<<queuenum(ProducerWaitQueue)<<endl;
                    //outqueue(ProducerWaitQueue);
                }
            }
        }
        //输出就绪队列
		element=HasElement(ReadyQueue);
        if(HasElement(ReadyQueue)){
            cout<<"就绪队列中有以下进程:"<<endl;
            DisPlay(ReadyQueue);
        }
        else
            cout<<"就绪队列中没有进程"<<endl;
        //输出生产者等待队列
        if(queuenum(ProducerWaitQueue)!=0){
            cout<<"生产者等待队列中有以下进程:"<<endl;
            DisPlay(ProducerWaitQueue);
        }
        else
            cout<<"生产者等待队列中没有进程"<<endl;
        //输出消费者等待队列 
        if(queuenum(ConsumerWaitQueue)!=0){
            cout<<"消费者等待队列中有以下进程:"<<endl;
            DisPlay(ConsumerWaitQueue);
        }
        else
            cout<<"消费者等待队列中没有进程"<<endl;
        cout<<endl; 
    }
    cout<<"最终over队列中生产者消费者id为"<<endl;
    DisPlay1(over);
    return 0;
}

(1)创建生产者消费者线程 在Windows2000环境下,创建一个控制台进程,在此进程创建n个线程来模拟生产者或者消费者。这些线程的信息由本程序定义的“测试用例文件”予以指定。 该文件的格式和含义如下: 3 1 P 3 2 P 4 3 C 4 1 4 P 2 5 C 3 1 2 4 第一行说明程序设置几个临界,其余每行分别描述了一个生产者或者消费者线程的信息。每一行的各字段间用Tab键隔开。不管是消费者还是生产者,都有一个对应的线程号,即每一行开始字段那个整数。第二个字段用字母P或者C分是生产者还是消费者。第三个字段表示在进入相应线程后,在进行生产和消费动作前的休眠时间,以秒计时;这样做的目的是可以通过调整这一列参数,控制开始进行生产和消费动作的时间。如果是代表生产者,则该行只有三个字段。如果代表消费者,则该行后边还有若干字段,代表要求消费的产品所对应的生产者的线程号。所以务必确认这些对应的线程号存在并且该线程代表一个生产者。 (2)生产和消费的规则 在按照上述要求创建线程进行相应的读写操作时,还需要符合以下要求: ①共享缓冲存在空闲空间时,生产者即可使用共享缓冲。 ②从上边的测试数据文件例子可以看出,某一生产者生产一个产品后,可能不止一个消费者,或者一个消费者多次地请求消费该产品。此时,只有当所有的消费需求都被满足以后,该产品所在的共享缓冲才可以被释放,并作为空闲空间允许新的生产者使用。 ③每个消费者线程的各个消费需求之间存在先后顺序。例如上述测试用例文件包含一行信息“5 C 3 l 2 4”,可知这代表一个消费者线程,该线程请求消费1,2,4号生产者线程生产的产品。而这种消费是有严格顺序的,消费1号线程产品的请求得到满足后才能继续往下请求2号生产者线程的产品。 ④要求在每个线程发出读写操作申请、开始读写操作和结束读写操作时分别显示提示信息。 (3)相关基础知识 本实验所使用的生产者消费者模型具有如下特点: 本实验的多个缓冲不是环形循环的,也不要求按顺序访问。生产者可以把产品放到目前某一个空缓冲消费者只消费指定生产者的产品。 在测试用例文件指定了所有的生产和消费的需求,只有当共享缓冲的数据满足了所有关于它的消费需求后,此共享缓冲才可以作为空闲空间允许新的生产者使用。 本实验在为生产者分配缓冲时各生产者间必须互斥,此后各个生产者的具体生产活动可以并发。而消费者之间只有在对同一产品进行消费时才需要互斥,同时它们在消费过程结束时需要判断该消费对象是否已经消费完毕并清除该产品。 Windows用来实现同步和互斥的实体。在Windows,常见的同步对象有:信号量(Semaphore)、互斥量(Mutex)、临界段(CriticalSection)等。使用这些对象都分为三个步骤,一是创建或者初始化:接着请求该同步对象,随即进入临界,这一步对应于互斥量的上锁;最后释放该同步对象,这对应于互斥量的解锁。这些同步对象在一个线程创建,在其他线程都可以使用,从而实现同步互斥。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值