操作系统实验 生产者/消费者模型
- 注:本文上半部分为原理,下半部分为实现
生产者 / 消费者模型:
生产者消费者模型具体来讲,就是在一个系统中,存在生产者和消费者两种角色,它们通过内存缓冲区进行通信。
概况描述:
· 两个或者更多的进程(线程)共享同一个缓冲区;
· 其中一个或多个进程(线程)作为“生产者”向缓冲区中添加数据;
· 另一个或者多个进程(线程)作为“消费者”从缓冲区中取走数据;
· 生产者和消费者必须互斥的使用缓冲区;
· 缓冲区空时,消费者不能读取数据;
· 缓冲区满时,生产者不能添加数据。
优点:
(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;
}
实现结果:
操作系统实验 生产者/消费者模型相关推荐
- 操作系统:生产者消费者模型的两种实现(C++)
文章目录 生产者消费者模型 什么是生产者消费者模型 生产者消费者模型的321原则 生产者消费者模型的优点 生产者消费者模型的实现方法 基于循环队列,信号量实现 基于阻塞队列,互斥锁.条件变量实现 生产 ...
- 操作系统实验 生产者消费者问题详解
操作系统课程设计 生产者消费者实验报告 一.实验目的 加深对进程概念的理解,明确进程与程序的区别. 认识并发执行的本质. 理解和掌握Linux和Windows进程通信系统调用的功能,通过实验和学习,提 ...
- 操作系统 —— 生产者消费者模型
文章目录 1. 生产者消费者模型的理解 1.1 串行的概念 1.2 并行的概念 1.3 简单总结: 2. 基于阻塞队列(block queue)实现此模型 2.1 阻塞队列的实现 2.2 使用阻塞队列 ...
- 【SEUSE】操作系统实验:消费者-生产者问题
操作系统实验:消费者-生产者问题 README 一.实验目的 二.实验内容 三.实验步骤 四.主要数据结构及其说明 五.程序运行时的初值和运行结果 六.实验体会 七.源程序 README 本实验报告仅 ...
- 【操作系统】实现生产者消费者模型
最近在复习操作系统,随手写两种Java实现生产者消费者模型的方式 一.信号量 import java.util.Queue; import java.util.Random; import java. ...
- 操作系统 — 生产者消费者模型
生产者消费者模型 所谓的生产者消费者模型就是一个类似于队列一样的东西串起来,这个队列可以想像成一个存放产品的"仓库",生产者只需要关心这个 "仓库",并不需要关 ...
- C++编程模拟生产者消费者模型
生产者消费者问题是操作系统中典型的进程同步互斥问题,(英语:Producer-Consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同 ...
- 互斥锁、共享内存方式以及生产者消费者模型
守护进程 1.守护进程的概念 进程指的是一个正在运行的程序,守护进程也是一个普通进程 意思就是一个进程可以守护另一个进程 import time from multiprocessing import ...
- C++11 并发指南九(综合运用: C++11 多线程下生产者消费者模型详解)
前面八章介绍了 C++11 并发编程的基础(抱歉哈,第五章-第八章还在草稿中),本文将综合运用 C++11 中的新的基础设施(主要是多线程.锁.条件变量)来阐述一个经典问题--生产者消费者模型,并给出 ...
- 【Java 并发编程】多线程、线程同步、死锁、线程间通信(生产者消费者模型)、可重入锁、线程池
并发编程(Concurrent Programming) 进程(Process).线程(Thread).线程的串行 多线程 多线程的原理 多线程的优缺点 Java并发编程 默认线程 开启新线程 `Ru ...
最新文章
- java run_javarun
- 请描述一下 cookies,sessionStorage 和 localStorage 的区别?
- 人类能与人工智能共生吗?马斯克设想的“人脑接口”,是否可行?
- 2020-11-8(activity状态以及任务栈)
- 第四范式入围Forrester Wave™:预测分析与机器学习中国市场评测报告 位列领导者行列...
- 计算机辅助药物设计局限,计算机辅助药物设计高效低耗
- python工作岗位要求_Python就业:Python就业岗位职能要求解析
- python文件内容倒序_python实现对列表中的元素进行倒序打印
- java随机生成数字代码,详解系列文章
- DMTF云计算开放管理标准内容
- Himall商城普通帮助类(二)
- 用友U9 BP不执行
- 系统更新后出现dll文件丢失问题
- 力扣(566.303)补8.25
- Html源代码图片解密,通过图片加密、解密文件
- 阿里大鱼发送短信(工具类)
- 全球及中国生物识别技术产业应用趋势及投资风险分析报告2021-2027年
- 实验五 网络编程与安全 20162316 刘诚昊
- 项目管理中绩效考核如果实施(3)(转)
- 纸牌游戏梭哈设计制作(C语言)