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

2023-05-16

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

操作系统:用c++模拟生产者消费者问题 的相关文章

  • window系统消失的c盘,实际占用与显示占用相差好多G

    问题 C盘一直显示的红色提醒 我c盘实际占用的空间只有33 1GB 而我的c盘总共大小是59 9GB 显示的剩余大小是1 35GB 也就是说我占用了58 11 和c盘的总文件大小相差了25GB 那么消失的25GB去了哪里 我百度过这个问题
  • texlive支持中文的简单方法

    1 确保tex文件的编码方式是UTF 8 2 在文档开始处添加一行命令即可 即 usepackage UTF8 ctex 如下所示 documentclass article usepackage UTF8 ctex begin artic
  • Tomcat7安装及配置教程

    Apache Tomcat7 0安装及配置教程 Apache Tomcat7 0官方网站链接 http tomcat apache org apache tomcat 7 0 73 windows x64 先解压下载的压缩包 然后在bin目
  • unix环境高级编程——文件IO

    本期主题 unix环境高级编程 文件IO 文件IO 0 引言 1 文件描述符 2 IO编程中常用的API接口 1 open函数 2 close函数 3 read函数 4 write函数 5 lseek函数 3 函数sync fsync和fd
  • 掉电无法启动数据库问题解决

    由于突然掉电 造成客户在windows平台上10 2 0 1数据库无法驱动 以下是具体解决步骤 一 定位故障问题 1 启动数据库 查看错误 SQL gt startup ora 01113 file 1 needs media recove
  • Linux网络安全-Zabbix入门(一)

    一 基本概念 1 监控目的 运行情况 提前发现问题 2 监控资源类别 公开 tcp udp 端口 私有 cpu 磁盘 监控一切需要监控的东西 只要能够想到 能够用命令实现的都能用来监控 如果想远程管理服务器就有远程管理卡 比如Dell id
  • 操作系统学习(九)进程通信

    一 知识总览 二 定义 进程通信是指进程之间的信息交换 每个进程都拥有自己的内存空间 是相互独立的 这样在每个进程执行时 才不会被其他进程所干扰 三 进程通信的方式 1 共享存储 1 两个进程对共享区的访问必须是互斥的 即在同一时间内 只允
  • 虚拟内存的最大容量与实际容量区别

    虚拟内存的最大容量与实际容量区别 1 概念介绍 虚拟内存的最大容量是计算机的地址结构 CPU寻址范围决定的 虚拟内存的实际容量是内存与外存之和 CPU寻址范围 两者的最小值 2 例题介绍 某计算机的地址结构是64位 按字节编址 内存大小51
  • 设备管理过程

    复杂度2 5 机密度2 5 最后更新2021 04 19 AIX中对设备会有如下五个操作 define aix下能看到设备的定义 但驱动程序并没有加载或初始化 该设备不可用 lsdev看到设备时defined 很多逻辑设备 vg lv等 只
  • 虚拟机管理程序、虚拟化和云: 深入剖析 PowerVM 虚拟机管理程序

    预备知识 Power 是没有限制的虚拟化 一些企业打算依靠 PowerVM 虚拟化将多个工作负载整合到较少系统上 从而提高服务器利用率 降低成本 Power VM 为基于 Power Systems 平台的高级 RAS 功能和领先性能为 A
  • Linux 磁盘与文件系统管理(鸟哥私房菜)

    本文来自 http vbird dic ksu edu tw linux basic 0230filesystem php 第八章 Linux 磁盘与文件系统管理 系统管理员很重要的任务之一就是管理好自己的磁盘文件系统 每个分割槽不可太大也
  • office2013 excel 打开时提示excel词典xllex.dll文件丢失或损坏

    今天打开Excel时 发现报错 xllex dll文件丢失或损坏 我用的是office2013 网上找了好多都是2007的dll文件 导入不了 于是乎重装office 问题解决 但还是把xllex dll烤出来做个备份吧 参考下面步骤即可
  • InfoQ视频直播分享报名:前贝尔实验室、Oracle架构师为你在线揭秘分布式平台内核...

    报名方式 关注InfoQ微信公众号 ID infoqchina 回复 InfoQ 即可观看在线直播技术分享 分享地点 u0026amp 时间 InfoQ直播微课堂将在熊猫 TV 网站播出 看腻了卖肉的女主播 来看看QCon 的明星讲师如何
  • 操作系统笔记六(文件管理)

    1 文件逻辑结构 1 1逻辑结构的文件类型 分类 有结构文件 例如 PNG文件 无结构文件 1 2顺序文件 1 3索引文件 2 辅存的存储空间分配 2 1分配方式 连续分配 直接分配连续的存储空间 链接分配 隐式链接 在盘块内指定下一个盘块
  • 《一个操作系统的实现》读书笔记-- 第一章--最小的“操作系统”

    一 最简单的 操作系统 最最简单的 操作系统 就是一个最最简单的引导扇区 Boot Sector 虽然它不具有任何功能 但是它却能够直接在裸机上运行 不依赖其他软件 一个引导扇区是512个字节 并且以0xAA55为结束标识的扇区 下面就是那
  • Linux系统如何看目录属于哪个磁盘分区

    Linux是先有目录 再有磁盘分区 df h 目录 例如 没有挂载磁盘的目录 显示在系统盘 root iZ2ze57v3n0zma46zqiq8nZ sh 1 5 5 df h alidata Filesystem Size Used Av
  • 由于回车符引起的shell错误

    今天弟弟写shell时出现一个错误 源代码如下 zip r 1 2 执行时出现错误 我也写了相同的语句 发现是可以执行的 把两个文件对比一看 差别在于 出错shell 正确shell 在linux下的回车是 n 在win下面的回车是 r n
  • Common块和Bss段的区别

    昨天看 程序员的自我修养 链接 装载与库 发现不是很理解为什么要用common块 然后仔细看了一番 有了自己的理解 common块 用来存放弱符号 而全局未初始化变量是弱符号 但是难道不是应该存放在 bss段吗 为什么要有common块呢
  • 地址映射与共享

    跟踪地址映射过程 1 通过命令 dbg asm启动调试器 在linux 0 11运行test c文件 使其进入死循环 我们的任务就是找到i的地址并将其修改为0使test c程序退出循环 2 在命令行输入crit c使Boch暂停 一般会显示
  • 【操作系统xv6】学习记录4-一级页表与二级页表

    占位

随机推荐

  • 【Vxworks操作系统】系统介绍与系统组成-NO.1

    目录 1 VxWorks系统介绍 2 VxWorks特点 3 vxWorks操作系统的组成 1 xff09 实时操作系统核心Wind 2 xff09 I O系统 3 xff09 文件系统 4 xff09 板级支持包 xff08 BSP xf
  • 【Vxworks操作系统】实时多任务介绍-NO.2

    目录 实时多任务 1 1 任务生命周期管理 1 2 任务状态控制 1 3 任务调度 1 4 用户接口 结语 xff1a 实时操作系统是基于多任务和任务间通信的概念的操作系统 xff0c 多任务环境允许一个实时应用由一组各自独立的任务组成 x
  • HDU 6298(数学)

    题意是给出一个数 xff0c 找出这个数的三个因子且这三个因子的和等于这个数 xff0c 输出满足条件的乘积最大的一组因子的乘积 xff0c 如果不存在这样的因子 xff0c 就输出 1 第一次 wa 了 xff0c 因为把题目中的 x n
  • libevent的http服务详解

    libevent的http服务详解 即远程调用 xff0c 得到一个call ID然后验证外部远程参数 span class token function evrpc request cb span span class token pun
  • 创建物理卷报错Can‘t open /dev/sdb1 exclusively. Mounted filesystem?以及对应的解决方法

    创建物理卷报错Can 39 t open dev sdb1 exclusively Mounted filesystem 以及对应的解决方法 一 xff1a 报错二 xff1a 解决方法 一 xff1a 报错 1 添加一块硬盘 2 对硬盘分
  • windows server 2012r2 开启远程桌面

    电脑 右键 属性 远程设置 允许远程连接此计算机 勾选 选择用户 添加administrator 开始 运行 gpedit msc 计算机配置 管理模板 Windows组件 远程桌面服务 连接 允许用户通过使用远程桌面服务进行远程连接 打开
  • Obsidian 多端同步实现

    原文地址 1 前言 如何将 windows 和 android 端的 obsidian 同步 xff1f 可以选择官方的 Obsidian Sync 服务 xff0c 或者使用 FolderSync 等同步工具 本文介绍一种基于 Git 的
  • Github Page 个人主页——项目部署

    本人博客 一 前言 想搭建自己的网站吗 xff1f 通常需要买一台服务器 xff0c 购买一个域名进行备案后 xff0c 解析到自己的服务器 xff0c 还要搭建环境 xff0c 后期运维等等 本文提供一种基于 Github Page 服务
  • Github Page 个人主页——CDN加速

    原文地址 1 前言 前两篇文章介绍了 如何部署静态网站 以及 给网站自定义域名 xff0c 到目前为止 xff0c 您已经拥有一个使用自己的域名的网站了 在访问个人网页时 xff0c 实质上是去Github的服务器上取资源的 xff0c 但
  • Github Page 个人主页——Hexo博客

    原文地址 一 前言 在前三篇文章介绍了如何部署一个属于自己的站点网页 xff0c 但是只有个人主页有些单调 xff0c Github Page 的本质是部署web站点 xff0c 所以不仅可以部署个人主页 xff0c 还可以将自己的博客部署
  • Android 开发——环境搭建

    原文地址 一 前言 1 1 Android Studio 简介 Android Studio 是谷歌推出的一个Android集成开发工具 xff0c 基于IntelliJ IDEA 类似 Eclipse ADT xff0c Android
  • 【Matlab】音频信号谱分析及椭圆滤波处理

    前言 一个使用matlab对音频信号进行频谱分析及滤波处理的学习笔记 xff0c 本文使用的是椭圆滤波器 音频下载 demo mp3 频谱分析 读取音频信号进行傅里叶变换 x fs 61 audioread 39 D demo mp3 39
  • 【Matlab】BPSK二进制相移键控波形生成

    前言 一个通信原理课程中使用Matlab生成BPSK波形的实验笔记 内容 设发送二进制信息为10011101 xff0c 码元速率为1波特 xff0c 载波 sin wt xff0c 幅值为1 xff0c 初始相位为0 当载波频率为2Hz
  • 【转】【面试】如果你这样回答“什么是线程安全”,面试官都会对你刮目相看...

    有读者跟我说 xff0c 喜欢看我的文章 xff0c 说很容易读 xff0c 我确实在易读性上花费的心思不亚于在内容上 因为我不喜欢一上来就堆很多东西 xff0c 而且把简单的东西搞得复杂人人都会 xff0c 但是把复杂的东西讲的简单 xf
  • 【Matlab】2FSK二进制频移键控波形生成

    前言 一个通信原理课程中使用Matlab生成2FSK波形的实验笔记 内容 设发送二进制信息为10011101 xff0c 码元速率为1波特 xff0c 载波 cos wt xff0c 幅值为1 xff0c 初始相位为0 当载波频率分别为3H
  • 【Matlab】QPSK四进制绝对相移调制波形生成

    前言 一个通信原理课程中使用Matlab生成QPSK波形的实验笔记 内容 设发送二进制信息为10011101 xff0c 码元速率为1波特 xff0c 载波 sin wt xff0c 幅值为1 xff0c 初始相位为0 当载波频率为2Hz
  • 【Matlab】DQPSK四进制相对相移调制波形生成

    前言 一个通信原理课程中使用Matlab生成DQPSK波形的实验笔记 内容 设发送二进制信息为10011101 xff0c 码元速率为1波特 xff0c 载波 sin wt xff0c 幅值为1 xff0c 初始相位为0 当载波频率为2Hz
  • archlinuxmanjaro安装中文输入法(fcitx5)

    archlinux manjaro安装中文输入法 xff08 fcitx5 xff09 装好了manjaro xff0c 但是他并没有我们的母语中文的输入法 xff0c 这要怎么办呢 xff1f 当然是自己装了 xff08 又水了好几句 x
  • vm安装centos7系统后,使用ifconfig命令 ens33 没有IP地址

    这个问题目前发现俩种情况 1 没有配置ens33文件 2 配置了 ens33文件 xff0c 重启后又没有ip地址了 问题一解决 xff1a 安装好centos7后 xff0c 使用ifconfig命令 xff0c 发现 ens33 没有i
  • 操作系统:用c++模拟生产者消费者问题

    操作系统 xff1a 用c 43 43 模拟生产者消费者问题 一 实验目的 xff1a 通过实验模拟生产者与消费者之间的关系 xff0c 了解并掌握他们之间的关系及其原理 由此增加对进程同步的问题的了解 二 实验要求 xff1a 每个进程有