• 注:本文上半部分为原理,下半部分为实现

生产者 / 消费者模型:
生产者消费者模型具体来讲,就是在一个系统中,存在生产者和消费者两种角色,它们通过内存缓冲区进行通信。

概况描述:
· 两个或者更多的进程(线程)共享同一个缓冲区;
· 其中一个或多个进程(线程)作为“生产者”向缓冲区中添加数据;
· 另一个或者多个进程(线程)作为“消费者”从缓冲区中取走数据;
· 生产者和消费者必须互斥的使用缓冲区;
· 缓冲区空时,消费者不能读取数据;
· 缓冲区满时,生产者不能添加数据。

优点:
(1) 解耦:
· 因由缓冲区做交互中介,生产者和消费者并不直接相互调用;
· 其实就是把生产者和消费者之间的耦合解开,变成了生产者和缓冲区消费者和缓冲区之间的耦合。

(2) 支持并发:
若消费者直接从生产者拿数据,消费者需要等待生产者生产数据;
同理,生产者需要等待消费者消费数据。

而在生产者/消费者模型中:
· 生产者和消费者是两个独立的并发主体。
· 生产者把制造出来的数据添加到缓冲区,即可去生产下一个数据。
· 同理,消费者从缓冲区中读取数据,不需要等待生产者生产数据。
· 如此,生产者和消费者就可以并发的执行。

(3)支持忙闲不均:
· 假设没有缓冲区,且消费者和生产者的速度不匹配,则会造成CPU的浪费。
· 生产者/消费者模型使得生产者/消费者的处理能力达到一个动态的平衡。

—————————————————————————————

试验任务:

①由用户指定要产生的进程及其类别,存入进入就绪队列。

②调度程序从就绪队列中提取一个就绪进程运行。
③如果申请的资源被阻塞则进入相应的等待队列,则调度程序调度就绪队列中的下一个进程。
④进程运行结束时,会检查对应的等待队列,
⑤激活相应等待队列中的进程进入就绪队列。
⑥运行结束的进程进入over链表(用于记录进程完成顺序)。
⑦重复这一过程直至就绪队列为空。

⑧程序询问是否要继续?如果要转至①开始执行,否则退出程序。

  • 每个进程由一个进程控制块(PCB)表示。进程控制块可以包含如下信息:进程类型标号、进程系统号、进程状态、进程链指针等等。
  • 系统开辟了一个缓冲区,大小由buffersize指定。
  • 程序中的链队列 / 链表:
    1.一个就绪队列
    2.两个等待队列:生产者等待队列和消费者等待队列
    3.一个over链表,用于收集已经运行结束的进程
    注:初始化时还可以添加生产者进程队列和消费者进程队列以便观察

C语言代码实现:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define MAX_SIZE 20
#define BUFFER_SIZE 3 typedef struct PCB_Type{int type; int pid; // 0 ~ 9int state;//0 or 1 int priority;//1 ~ 10  本实验中暂时用不到int time;//1 ~ 50   本实验中暂时用不到struct PCB_Type *next;}PCB,*Linklist;//初始化10个PCB
//type产生随机数0或1,表示进程类型,1为生产者进程,0为消费者进程;
//state为1代表就绪状态,state为0代表等待状态
void Inet_list(PCB *producer_list , PCB *comsumer_list){PCB *p = producer_list;PCB *c = comsumer_list;int i=0;while(i<11){PCB *tmp = (PCB *)malloc(sizeof(PCB)); tmp->type = rand()%2;//随机生成进程类型 tmp->pid = i;tmp->state = 1;//根据实验要求,所有进程一开始都进入就绪队列 tmp->priority = rand()%10+1;tmp->time = rand()%50+1;//printf("id:%d || type:%d\n",tmp->pid,tmp->type); //生成测试语句 if(tmp->type == 1){p->next = tmp;p = tmp;p->next = NULL;}if(tmp->type == 0){c->next = tmp;c = tmp;c->next = NULL;} i++;  }
}void show_list(PCB *p){PCB *q = p->next;if(!q){printf("空!\n");}else{while(q){printf("%d  ",q->pid);q = q->next;}putchar('\n');}
}void sort_ready(PCB *producer_list, PCB *comsumer_list, PCB *ready_list){  //初始化就绪队列 PCB *p = producer_list->next;PCB *c = comsumer_list->next;PCB *tail = ready_list;tail->next = NULL;PCB *t;while(p && c){if(p->pid < c->pid){t = p;p = p->next;}else{t = c;c = c->next;}t->next = NULL;tail->next = t;tail = t;}if(p) tail->next = p;if(c) tail->next = c;
}//执行就绪队列中的程序
//如果申请的进程被阻塞: 则进入相应的等待队列,调度程序调度就绪队列中的下一个进程。
void Do(PCB *ready_list , PCB *p_wait_list, PCB *c_wait_list, PCB *over_list, int *buffer_data, int *buffer_blank){PCB *r = ready_list->next;
PCB *o = over_list;
PCB *cw = c_wait_list;
PCB *pw = p_wait_list;if(r->type == 1){printf(" %d进程为生产者进程!",r->pid); if(*buffer_blank>0){ //如果缓存区还有空位 printf("成功加入缓存区!\n"); //printf("缓存区数据量:%d\n",buffer_data);--*buffer_blank;++*buffer_data;ready_list->next = r->next;//加入over list r->next=NULL;while(o->next  != NULL){o = o->next;} //找到over_list的最末尾位置 o->next = r; } else{ //如果缓存区没有空位 printf("阻塞!加入生产者等待队列!\n"); ready_list->next = r->next;r->next=NULL;r->state = 0;//等待状态下state为0; while(pw->next  != NULL){pw = pw->next;} //找到生产者等待队列的最末尾位置 pw->next = r;         }}if(r->type == 0){printf(" %d进程为消费者进程!",r->pid); if(*buffer_data>0){ //如果缓存区有数据缓存 printf("成功从缓存区取出一条数据!\n"); ++*buffer_blank;--*buffer_data;ready_list->next = r->next; //加入over list r->next=NULL;while(o->next  != NULL){o = o->next;} //找到over_list的最末尾位置 o->next = r; } else{ //如果缓存区没有数据 printf("阻塞!加入消费者等待队列!\n"); ready_list->next = r->next;r->next=NULL;r->state = 0;//等待状态下state为0; while(cw->next  != NULL){cw = cw->next;} //找到消费者等待队列最末尾位置 cw->next = r;      }}printf("检查等待队列......");  //进程结束,检查等待队列if(*buffer_data>0 && c_wait_list->next){ //如果缓存区有数据,激活消费者等待队列的首个进程 printf("激活消费者等待队列的首个进程,加入就绪队列!\n"); PCB *cw = c_wait_list->next;PCB *r = ready_list->next;c_wait_list->next = cw->next;ready_list->next = cw;cw->next = r;cw->state = 1;//就绪状态state为1; } else if(*buffer_blank>0 && p_wait_list->next){ //如果缓存区有存储空间,激活消费者等待队列的首个进程 printf("激活生产者等待队列的首个进程,加入就绪队列!\n"); PCB *pw = p_wait_list->next;PCB *r = ready_list->next;p_wait_list->next = pw->next;ready_list->next = pw;pw->next = r;pw->state = 1;//就绪状态state为1; } else{printf("等待队列中没有需要激活的进程!\n"); }
}void line(){printf("--------------------------------------------------\n");
}int main(){int judge = 1; //看到最后几行代码即可明白
while(judge==1){int buffer_data = 0;   //初始化缓存区 int buffer_blank = BUFFER_SIZE;PCB *producer_list = (PCB *)malloc(sizeof(PCB));  //生产者队列 (头节点不存信息) producer_list->next = NULL;PCB *p_wait_list = (PCB *)malloc(sizeof(PCB));  //生产者等待队列 (头节点不存信息) p_wait_list->next = NULL;PCB *comsumer_list = (PCB *)malloc(sizeof(PCB));  //消费者队列 (头节点不存信息) comsumer_list->next = NULL;PCB *c_wait_list = (PCB *)malloc(sizeof(PCB));  //消费者队列 (头节点不存信息) c_wait_list->next = NULL;PCB *ready_list = (PCB *)malloc(sizeof(PCB));  //就绪队列 (头节点不存信息) ready_list->next = NULL;PCB *over_list = (PCB *)malloc(sizeof(PCB));  //over链表 (头节点不存信息) over_list->next = NULL;Inet_list(producer_list,comsumer_list);   // 初始化生产者和消费者队列 printf("初始状态:\n");printf("生产者进程:");       show_list(producer_list);printf("消费者进程:"); show_list(comsumer_list);sort_ready(producer_list, comsumer_list, ready_list); //初始化就绪队列 printf("就绪队列:");show_list(ready_list);while(ready_list->next) {line();Do(ready_list , p_wait_list, c_wait_list, over_list, &buffer_data, &buffer_blank);printf("就绪队列:");show_list(ready_list);printf("生产者等待队列:");show_list(p_wait_list);printf("消费者等待队列:");show_list(c_wait_list);printf("已完成进程:");show_list(over_list);printf("缓存区数据量:%d\n",buffer_data);printf("缓存区剩余存储量:%d\n",buffer_blank); }line();printf("是否继续?\n");printf("1 ————是,继续执行程序!\n");printf("0 ————否,退出程序!\n");printf("请输入您的选择:") ;int temp;scanf("%d",&temp);judge = temp; if(judge == 0){printf("退出程序!");}
}return 0;
}

实现结果:


操作系统实验 生产者/消费者模型相关推荐

  1. 操作系统:生产者消费者模型的两种实现(C++)

    文章目录 生产者消费者模型 什么是生产者消费者模型 生产者消费者模型的321原则 生产者消费者模型的优点 生产者消费者模型的实现方法 基于循环队列,信号量实现 基于阻塞队列,互斥锁.条件变量实现 生产 ...

  2. 操作系统实验 生产者消费者问题详解

    操作系统课程设计 生产者消费者实验报告 一.实验目的 加深对进程概念的理解,明确进程与程序的区别. 认识并发执行的本质. 理解和掌握Linux和Windows进程通信系统调用的功能,通过实验和学习,提 ...

  3. 操作系统 —— 生产者消费者模型

    文章目录 1. 生产者消费者模型的理解 1.1 串行的概念 1.2 并行的概念 1.3 简单总结: 2. 基于阻塞队列(block queue)实现此模型 2.1 阻塞队列的实现 2.2 使用阻塞队列 ...

  4. 【SEUSE】操作系统实验:消费者-生产者问题

    操作系统实验:消费者-生产者问题 README 一.实验目的 二.实验内容 三.实验步骤 四.主要数据结构及其说明 五.程序运行时的初值和运行结果 六.实验体会 七.源程序 README 本实验报告仅 ...

  5. 【操作系统】实现生产者消费者模型

    最近在复习操作系统,随手写两种Java实现生产者消费者模型的方式 一.信号量 import java.util.Queue; import java.util.Random; import java. ...

  6. 操作系统 — 生产者消费者模型

    生产者消费者模型 所谓的生产者消费者模型就是一个类似于队列一样的东西串起来,这个队列可以想像成一个存放产品的"仓库",生产者只需要关心这个 "仓库",并不需要关 ...

  7. C++编程模拟生产者消费者模型

    生产者消费者问题是操作系统中典型的进程同步互斥问题,(英语:Producer-Consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同 ...

  8. 互斥锁、共享内存方式以及生产者消费者模型

    守护进程 1.守护进程的概念 进程指的是一个正在运行的程序,守护进程也是一个普通进程 意思就是一个进程可以守护另一个进程 import time from multiprocessing import ...

  9. C++11 并发指南九(综合运用: C++11 多线程下生产者消费者模型详解)

    前面八章介绍了 C++11 并发编程的基础(抱歉哈,第五章-第八章还在草稿中),本文将综合运用 C++11 中的新的基础设施(主要是多线程.锁.条件变量)来阐述一个经典问题--生产者消费者模型,并给出 ...

  10. 【Java 并发编程】多线程、线程同步、死锁、线程间通信(生产者消费者模型)、可重入锁、线程池

    并发编程(Concurrent Programming) 进程(Process).线程(Thread).线程的串行 多线程 多线程的原理 多线程的优缺点 Java并发编程 默认线程 开启新线程 `Ru ...

最新文章

  1. java run_javarun
  2. 请描述一下 cookies,sessionStorage 和 localStorage 的区别?
  3. 人类能与人工智能共生吗?马斯克设想的“人脑接口”,是否可行?
  4. 2020-11-8(activity状态以及任务栈)
  5. 第四范式入围Forrester Wave™:预测分析与机器学习中国市场评测报告 位列领导者行列...
  6. 计算机辅助药物设计局限,计算机辅助药物设计高效低耗
  7. python工作岗位要求_Python就业:Python就业岗位职能要求解析
  8. python文件内容倒序_python实现对列表中的元素进行倒序打印
  9. java随机生成数字代码,详解系列文章
  10. DMTF云计算开放管理标准内容
  11. Himall商城普通帮助类(二)
  12. 用友U9 BP不执行
  13. 系统更新后出现dll文件丢失问题
  14. 力扣(566.303)补8.25
  15. Html源代码图片解密,通过图片加密、解密文件
  16. 阿里大鱼发送短信(工具类)
  17. 全球及中国生物识别技术产业应用趋势及投资风险分析报告2021-2027年
  18. 实验五 网络编程与安全 20162316 刘诚昊
  19. 项目管理中绩效考核如果实施(3)(转)
  20. 纸牌游戏梭哈设计制作(C语言)

热门文章

  1. 短视频平台原创检测规则 伪原创制作
  2. 智能家居系统解决方案
  3. 微分几何 Class 2 欧氏空间
  4. 嘉应大学黄林鑫计算机学院,林鑫-中国科学院大学-UCAS
  5. [计算机组成原理]定点数运算及溢出检测
  6. 每一个梦想都要让它长上翅膀
  7. php微信银行卡rsa加密,企业付款到银行卡用RSA公钥加密银行卡号失败
  8. 如何用photoshop做24色环_Photoshop绘制超逼真的色轮/色环配色表效果图
  9. Vue中自定义指令directive的使用
  10. Texstudio 与 SumatraPDF双向搜索设置