操作系统:用c++模拟生产者消费者问题
一.实验目的:通过实验模拟生产者与消费者之间的关系,了解并掌握他们之间的关系及其原理。由此增加对进程同步的问题的了解。
二.实验要求:每个进程有一个进程控制块(PCB)表示。进程控制块可以包含如下信息:进程类型标号、进程系统号、进程状态、进程产品(字符)、进程链指针等等。系统开辟了一个缓冲区,大小由buffersize指定。程序中有三个链队列,一个链表。一个就绪队列(ready)。两个等待队列:生产者等待队列(producer),消费者等待队(consumer)。一个链表(over),用于收集已经运行结束的进程。本程序通过函数模拟信号量的原子操作。
三.实验内容:
1.由用户指定要产生的进程及其类别,且存入进入就绪队列。
2.调度程序从就绪队列中提取一个就绪进程运行。如果申请的资源被阻塞则进入相应的等待队列,调度程序调度就绪队列中的下一个进程。进程运行结束时,会检查对应的等待队列,激活队列中的进程进入就绪队列。运行结束的进程进入over链表。重复这一过程直至就绪队列为空。
3.程序询问是否要继续?如果要转至1开始执行,否则退出程序。
四.实验代码:
#include <iostream>
using namespace std;
int BUFFERSIZE;//定义缓冲区大小
int NOW_BUFFER; //定义此时缓冲区数据量
//进程PCB数据结构
typedef struct PCB{
int type; //0代表生产者,1代表消费者
int num;
int status;//0代表等待,1代表就绪
char product;
};
PCB p[100];//定义含100个元素的PCB数组
//队列节点
typedef struct QNode{
PCB data;
struct QNode *next;
}QNode;
//队列指针节点
typedef struct {
QNode* front;
QNode* rear;
}LinkQueue;
//初始化队列
void InitQueue(LinkQueue &Q){
Q.front=Q.rear=new QNode;
Q.front->next=NULL;
}
//入队
bool EnQueue(LinkQueue &Q,PCB e){
QNode* p=new QNode;
p->data=e;
p->next=NULL; Q.rear->next=p;
Q.rear=p;
// p=NULL;
return true;
}
//出队
bool DeQueue(LinkQueue &Q) {
if (Q.front == Q.rear)
return false;
else {
QNode *p = Q.front->next;
Q.front->next = p->next;
if (Q.rear == p)
Q.rear = Q.front;
delete p;
return true;
}
}
//取队头
PCB GetHead(LinkQueue Q){
PCB m;
m.type=-1;m.num=-1;m.status=-1;m.product='!';
if(Q.front!=Q.rear)
return Q.front->next->data;
else{
return m;
}
}
//遍历队列
void TravelQueue(LinkQueue Q){
QNode* p=Q.front;
if(p->next==NULL)
return;
while (p->next->next){
cout<<p->next->data.num<<"-->";
p=p->next;
}
cout<<p->next->data.num;
p=NULL;
}
//链表节点
typedef struct LNode{
PCB data;
struct LNode* next;
}LNode,*LinkList;
//初始化链表
void InitList(LinkList &L){
L=new LNode;
L->next=NULL;
}
//向链表输入数据
bool Add(LinkList &L,PCB e){
LinkList s=L;
while(s->next){
s=s->next;
}
LNode* p=new LNode;
p->data=e;
p->next=NULL;
s->next=p;
s=p;
return true;
}
void TravelList(LinkList L){
LNode* p=L;
if(p->next==NULL)
return;
while (p->next->next){
cout<<p->next->data.num<<"-->";
p=p->next;
}
cout<<p->next->data.num;
p=NULL;
}
//定义打印就绪队列,生产者等待队列,消费者等待队列,已完成进程队列函数
void Print(LinkQueue &ready,LinkQueue &producer,LinkQueue &customer,LinkList &over){
cout<<"就绪队列为:";
TravelQueue(ready);
cout<<endl;
cout<<"生产者等待队列为:";
TravelQueue(producer);
cout<<endl;
cout<<"消费者等待队列为:";
TravelQueue(customer);
cout<<endl;
cout<<"已完成进程为:";
TravelList(over);
cout<<endl;
cout<<"缓冲区数据量:"<<NOW_BUFFER<<endl;
cout<<"缓冲区剩余存储量:"<<BUFFERSIZE-NOW_BUFFER<<endl;
}
//进程运行函数
void Process(LinkQueue &ready,LinkQueue &producer,LinkQueue &customer,LinkList &over){
int i=0;
while(ready.front->next!=NULL){
cout<<"------------------------------"<<endl;
cout<<"第"<<i+1<<"轮"<<endl;
PCB first= GetHead(ready);
DeQueue(ready);
if(first.type==0){ //是0表示为生产者
cout<<"取就绪队列队头,"<<"该进程为:"<<first.num<<",是生产者进程"<<endl;
NOW_BUFFER++;
if(NOW_BUFFER<=BUFFERSIZE){ //缓冲区剩余位置足够,检查消费者就绪队列
PCB t= GetHead(customer);
if(t.num!=-1) { //消费者等待队列不为空
cout << "检查消费者等待队列,有消费者被阻塞,给予激活并加入就绪队列队头" << endl;
DeQueue(customer);
QNode* r=new QNode ; //将激活后的消费者进程加入就绪队列队头
if(ready.front!=ready.rear){
r->data=t;
r->next=ready.front->next;
ready.front->next=r;}
else{
r->data=t;
r->next=ready.rear->next;
ready.rear->next=r;
ready.rear=r;
}
Add(over,first); //将该进程加入over链表
Print(ready,producer,customer,over);
}
else{ //消费者等待队列为空
cout << "检查消费者等待队列,没有消费者被阻塞" << endl;
Add(over,first); //将该进程加入over链表中
Print(ready,producer,customer,over);
}
}
else{ //缓冲区剩余位置不够,阻塞该生产者进程并加入生产者等待队列
NOW_BUFFER--;
cout<<"缓冲区剩余量不够,该生产者进程被阻塞"<<endl;
EnQueue(producer,first); //入生产者等待队列
Print(ready,producer,customer,over);
}
}
else{ //是消费者
cout<<"取就绪队列队头,"<<"该进程为:"<<first.num<<",是消费者进程"<<endl;
NOW_BUFFER--;
if(NOW_BUFFER>=0){
PCB m= GetHead(producer);
if(m.num!=-1){ //生产者等待队列有进程
cout << "检查生产者等待队列,有生产者被阻塞,给予激活并加入就绪队列队头" << endl;
DeQueue(producer);
QNode* s=new QNode ; //将激活后的消费者进程加入就绪队列队头
if(ready.front!=ready.rear){
s->data=m;
s->next=ready.front->next;
ready.front->next=s;
}
else{
s->data=m;
s->next=ready.rear->next;
ready.rear->next=s;
ready.rear=s;
}
Add(over,first);
Print(ready,producer,customer,over);
}
else{ //生产者队列为空
cout << "检查生产者等待队列,没有生产者被阻塞" << endl;
Add(over,first);
Print(ready,producer,customer,over);
}
}
else{ //缓冲区数据量不够,阻塞该消费者进程并加入消费者等待队列
NOW_BUFFER++;
cout<<"缓冲区剩数据量不够,该消费者进程被阻塞"<<endl;
EnQueue(customer,first); //入生产者等待队列
Print(ready,producer,customer,over);
}
}
i++;
}
}
int main() {
while(1) {
int number;//定义进程数量
LinkQueue ready; //定义就绪队列
LinkQueue producer, customer; //定义一个生产者等待队列,一个消费者等待队列
LinkList over; //定义一个over链表,收集已经运行结束的程序
InitQueue(ready); //初始化就绪队列
InitQueue(producer);
InitQueue(customer);
InitList(over); //初始化生产者消费者等待队列和over链表
cout << "------------------------------" << endl;
cout << "请输入您要加入的进程数量(0-100):";
cin >> number;
cout << "请输入缓冲区容量:";
cin >> BUFFERSIZE; //输出缓冲区容量
NOW_BUFFER = 0; //此时缓冲区剩余空间为缓冲区容量
for (int i = 0; i < number; i++) {
cout << "------------------------------" << endl;
cout << "请输入第" << i + 1 << "个进程信息:" << endl;
cout << "进程类型(0代表生产者,1代表消费者):";
cin >> p[i].type;
cout << "进程号码(0-" << number - 1 << "):";
cin >> p[i].num;
p[i].status = 1;//初始化都为就绪态
cout << "进程产品:";
cin >> p[i].product;
}
cout << "------------------------------" << endl;
for (int i = 0; i < number; i++) { //将进程全部入就绪队列
if (p[i].status == 1)
EnQueue(ready, p[i]);
}
Print(ready, producer, customer, over);
Process(ready, producer, customer, over);
cout << "------------------------------" << endl;
cout << "是否继续?(y/n)?" << endl;
char t;
cin>>t;
if (t == 'n') {
exit(0);
}
}
return 0;
}