操作系统:用c++模拟生产者消费者问题

操作系统:用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;
}

  • 6
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实验题目: 生产者消费者(综合性实验) 实验环境: C语言编译器 实验内容: ① 由用户指定要产生的进程及其类别,存入进入就绪队列。    ② 调度程序从就绪队列中提取一个就绪进程运行。如果申请的资源被阻塞则进入相应的等待队列,调度程序调度就绪队列中的下一个进程。进程运行结束时,会检查对应的等待队列,激活队列中的进程进入就绪队列。运行结束的进程进入over链表。重复这一过程直至就绪队列为空。    ③ 程序询问是否要继续?如果要转直①开始执行,否则退出程序。 实验目的: 通过实验模拟生产者消费者之间的关系,了解并掌握他们之间的关系及其原理。由此增加对进程同步的问题的了解。 实验要求: 每个进程有一个进程控制块(PCB)表示。进程控制块可以包含如下信息:进程类型标号、进程系统号、进程状态、进程产品(字符)、进程链指针等等。 系统开辟了一个缓冲区,大小由buffersize指定。 程序中有三个链队列,一个链表。一个就绪队列(ready),两个等待队列生产者等待队列(producer);消费者队列(consumer)。一个链表(over),用于收集已经运行结束的进程 本程序通过函数模拟信号量的操作。 参考书目: 1)徐甲同等编,计算机操作系统教程,西安电子科技大学出版社 2)Andrew S. Tanenbaum著,陈向群,马红兵译. 现代操作系统(第2版). 机械工业出版社 3)Abranham Silberschatz, Peter Baer Galvin, Greg Gagne著. 郑扣根译. 操作系统概念(第2版). 高等教育出版社 4)张尧学编著. 计算机操作系统教程(第2版)习题解答与实验指导. 清华大学出版社 实验报告要求: (1) 每位同学交一份电子版本的实验报告,上传到202.204.125.21服务器中。 (2) 文件名格式为班级、学号加上个人姓名,例如: 电子04-1-040824101**.doc   表示电子04-1班学号为040824101号的**同学的实验报告。 (3) 实验报告内容的开始处要列出实验的目的,实验环境、实验内容等的说明,报告中要附上程序代码,并对实验过程进行说明。 基本数据结构: PCB* readyhead=NULL, * readytail=NULL; // 就绪队列 PCB* consumerhead=NULL, * consumertail=NULL; // 消费者队列 PCB* producerhead=NULL, * producertail=NULL; // 生产者队列 over=(PCB*)malloc(sizeof(PCB)); // over链表 int productnum=0; //产品数量 int full=0, empty=buffersize; // semaphore char buffer[buffersize]; // 缓冲区 int bufferpoint=0; // 缓冲区指针 struct pcb { /* 定义进程控制块PCB */ int flag; // flag=1 denote producer; flag=2 denote consumer; int numlabel; char product; char state; struct pcb * processlink; …… }; processproc( )--- 给PCB分配内存。产生相应的的进程:输入1为生产者进程;输入2为消费者进程,并把这些进程放入就绪队列中。 waitempty( )--- 如果缓冲区满,该进程进入生产者等待队列;linkqueue(exe,&producertail); // 把就绪队列里的进程放入生产者队列的尾部 void signalempty() bool waitfull() void signalfull() void producerrun() void comsuerrun() void main() { processproc(); element=hasElement(readyhead); while(element){ exe=getq(readyhead,&readytail); printf("进程%d申请运行,它是一个",exe->numlabel); exe->flag==1? printf("生产者\n"):printf("消费者\n"); if(exe->flag==1) producerrun();
生产者-消费者问题操作系统中经典的进程同步问题之一。在C语言中,可以使用多线程来实现生产者-消费者模型。下面是一个使用C语言多线程实现生产者-消费者模型的示例代码: ```c #include <iostream> #include <random> #include <time.h> #include <thread> #include <Windows.h> using namespace std; class Buffer { private: int size; int* buffer; int in; int out; int count; public: Buffer(int bufferSize) { size = bufferSize; buffer = new int[size]; in = 0; out = 0; count = 0; } void insert(int item) { while (count == size) { // 缓冲区已满,等待消费者消费 Sleep(1000); } buffer[in] = item; in = (in + 1) % size; count++; } int remove() { while (count == 0) { // 缓冲区为空,等待生产者生产 Sleep(1000); } int item = buffer[out]; out = (out + 1) % size; count--; return item; } }; // 生产者线程 void producer(Buffer* buffer) { static uniform_int_distribution<unsigned> u(1, 100); static default_random_engine e(time(0)); for (int i = 0; i < 20; i++) { int item = u(e); buffer->insert(item); Sleep(1000); } } // 消费者线程 void consumer(Buffer* buffer) { default_random_engine v(time(0)); for (int i = 0; i < 20; i++) { buffer->remove(); Sleep(2000); } } int main() { Buffer buffer(10); // 缓冲区大小为10 thread producerThread(producer, &buffer); thread consumerThread(consumer, &buffer); producerThread.join(); consumerThread.join(); cout << "结束!" << endl; return 0;} ``` 此示例代码中,使用了C++11的线程库来创建生产者线程和消费者线程,并通过`Buffer`类模拟了一个有界缓冲区。生产者线程调用`insert`方法往缓冲区中插入数据,消费者线程调用`remove`方法从缓冲区中取出数据。为了保证同步,生产者线程和消费者线程在访问缓冲区时都使用了互斥锁。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值