生产者消费者模型

56 篇文章 0 订阅

一、什么是生产者消费者模型
在实际的开发中,经常会碰到如下场景:某个模块负责生产数据,这些数据由另一个模块来负责处理。产生数据的模块就形象的称为生产者,而处理数据的模块就称为消费者。只有生产者和消费者还不够,这个模型还必须要有一个缓冲区处于生产者和消费者之间,作为中介。生产者把数据放入缓冲区,而消费者从缓冲区中取出数据。
这里写图片描述

二、为什么要使用生产者消费者模型
1、解耦
假设生产者和消费者是两个类,如果让生产者直接调用消费者的某个函数,那么生产者和消费者之间就会产生依赖(耦合)。如果消费者的代码发生变化可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合性也就降低了。

2、支持并发
生产者直接调用消费者的某个方法,还有一个弊端。由于函数调用是同步的(或者称作阻塞的),在消费者的方法没有返回之前,生产者只好一值阻塞,如果消费者处理数据很慢,则生产者就会白白浪费时间。使用生产者和消费者模式之后,生产者和消费者可以是两个独立的并发主体。生产者把制造出来的数据放到缓冲区,就可以继续生产下一个数据,而不必依赖消费者的处理速度了。
3、支持忙闲不均
缓冲区还有一个好处就是,如果制造数据的速度时快时慢,缓冲区的好处就体现出来了,当数据制造快的时候,消费者来不及处理,未处理的数据就可存放到缓冲区中。等待生产者的速度慢下来之后,消费者再慢慢处理。

三、生产者消费的关系和特点
1、生产者和消费者的模型
1.1、单个生产者和单个消费者
1.2、单个生产者和多个消费者
1.3、多个生产者和单个消费者
1.4、多个生产者和多个消费者

2、生产者和消费者之间的关系
2.1、生产者和生产者之间是互斥关系
2.2、消费者和消费者之间是互斥关系
2.3、生产者和消费者之间是同步、互斥关系
也就是:
生产者生产的时候消费者不能消费
消费者消费的时候生产者不能生产
缓冲区空时消费者不能消费
缓冲区满时生产者不能生产

例: 生产者-消费者的例子,生产者生产一个结构体串在链表的表头上,消费者从表头取一个结构体。

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<stdlib.h>
#include<assert.h>

typedef struct Node
{
    int data;
    struct Node * next;
}Node,*Node_p,**Node_pp;

Node_p CreatNode(int data)
{
    Node_p _n=(Node_p)malloc(sizeof(Node));
    if(_n==NULL)
    {
        return NULL;
    }
    _n->data=data;
    _n->next=NULL;
    return _n;
}

void Init(Node_pp list)
{
    *list=CreatNode(0);
}

void PushFront(Node_p list ,int data)
{
    assert(list);
    Node_p _n=CreatNode(data);
    if(_n==NULL)
    {
        perror("Push");
        return;
    }

    _n->next=list->next;
    list->next=_n;
}

void del_Node(Node_p del)
{
    assert(del);
    free(del);
}

void PopFront(Node_p list,int *data)
{
    if(!isEmpty(list))
    {
        Node_p del=list->next;
        list->next=del->next;
        *data=del->data;
        del_Node(del);
    }
    else
    {
        printf("list Empty\n");
    }
}

int isEmpty(Node_p list)
{
    assert(list);
    if(list->next==NULL)
        return 1;
    else
        return 0;
}

void destroy(Node_p list)
{
    int data;
    assert(list);
    while(!isEmpty(list))
    {
        PopFront(list,&data);
    }
    del_Node(list);
}

void ShowList(Node_p list)
{
    assert(list);
    Node_p cur=list->next;
    while(cur->next)
    {
        printf("%d->",cur->data);
        cur=cur->next;
    }
    printf("\n");
}

Node_p list=NULL;
pthread_mutex_t mylock= PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t mycond=PTHREAD_COND_INITIALIZER;

void * Consumer(void *arg)
{
    int data=0;
    while(1)
    {
        pthread_mutex_lock(&mylock);
        while(isEmpty(list))
        {
            pthread_cond_wait(&mycond,&mylock);
        }
        PopFront(list,&data);
        pthread_mutex_unlock(&mylock);
        printf("consumer:%d\n",data);
    }
    return NULL;
}

void * Producer(void *arg)
{
    int data=0;
    while(1)
    {
        usleep(123456);
        data=rand()%1000;
        pthread_mutex_lock(&mylock);
        PushFront(list,data);
        pthread_mutex_unlock(&mylock);
        pthread_cond_signal(&mycond);
        printf("Producer:%d\n",data);
    }
    return NULL;
}

int main()
{
    Init(&list);
    pthread_t tid1,tid2;
    pthread_create(&tid1,NULL,Consumer,NULL);
    pthread_create(&tid2,NULL,Producer,NULL);
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    destroy(list);
    pthread_mutex_destroy(&mylock);
    pthread_cond_destroy(&mycond);
    return 0;
}
  • 12
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
这个是很经典的问题 实验题目: 生产者消费者(综合性实验) 实验环境: 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(); else comsuerrun(); element=hasElement(readyhead); } printf("就绪队列没有进程\n"); if(hasElement(consumerhead)) { printf("消费者等待队列中有进程:\n"); display(consumerhead); } else { printf("消费者等待队列中没有进程\n"); } if(hasElement(producerhead)) { printf("生产者等待队列中有进程:\n"); display(producerhead); } else { printf("生产者等待队列中没有进程\n"); } }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值