生产者消费者问题
来源:互联网 发布:ubuntu怎么安装wps 编辑:程序博客网 时间:2024/05/22 16:41
生产者消费者模型:
在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据
由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程
等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。
单单抽象出生产者和消费者,还够不上是生产者/消费者模式。该模式还需要
有一个缓冲区处于生产者和消费者之间,作为一个中介。生产者把数据放入缓冲区,
而消费者从缓冲区取出数据。大概的结构如下图。
为了不至于太抽象,我们举一个寄信的例子(虽说这年头寄信已经不时兴,但这个例
子还是比较贴切的)。
假设你要寄一封平信,大致过程如下:
1、你把信写好——相当于生产者制造数据
2、你把信放入邮筒——相当于生产者把数据放入缓冲区
3、邮递员把信从邮筒取出——相当于消费者把数据取出缓冲区
4、邮递员把信拿去邮局做相应的处理——相当于消费者处理数据
优点:
1.降低耦合
因为两者通过中间媒介缓冲区,所以耦合率降低,如果生产者/消费者代码有变化,
另一方受影响不大。
2.支持并发(concurrency)
生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的
(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一
消费者处理数据很慢,生产者就会浪费很多时间去等待。
3.支持忙闲不均
缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现
出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲
区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。
为了充分复用,我们拿寄信的例子来说事。假设邮递员一次只能带走1000封
信。万一某次碰上情人节(也可能是圣诞节)送贺卡,需要寄出去的信超过1000
封,这时候邮筒这个缓冲区就派上用场了。邮递员把来不及带走的信暂存在邮筒中,
等下次过来时再拿走。
生产者消费者模型中三种关系:
1.生产者和生产者(竞争关系)
2.消费者和消费者(竞争关系)
3.生产者和消费者(互斥与同步关系)
下面我们写个简单的例子,首先我们创建两个线程,线成1生产数据(PushFront),
线程2消费(PopFront)数据,我们使用pthread_mutex_lock(&mylock)进行加锁
(互斥锁)保护,以保证互斥,生产数据时不能消费数据,消费数据时不能生产数
据。
好了,不多说我们直接上代码:
#include<stdio.h>#include<assert.h>#include<unistd.h>#include<stdlib.h>#include<pthread.h>typedef struct Linknode {int _data;struct Linknode* _next;}node;pthread_mutex_t mylock=PTHREAD_MUTEX_INITIALIZER;pthread_cond_t mycond=PTHREAD_COND_INITIALIZER;node* CreatNode(int data){node* newNode=(node*)malloc(sizeof(node));if(newNode==NULL){perror("malloc failed\n");return NULL;}newNode->_data=data;newNode->_next=NULL;return newNode;}void InitLink(node** _head){*_head=CreatNode(0);}void PushFront(node *head,int data){ assert(head);//assert(data);node* newNode=CreatNode(data);newNode->_next=head->_next;head->_next=newNode;}void del_node(node* del){free(del);del=NULL;}int IsEmpty(node* head){assert(head);if(head->_next){return 0;}return 1;}void PopFront(node* head,int* data){assert(head);if(IsEmpty(head)>0){printf("list is empty\n");return;}else{ node* del=head->_next;*data=del->_data;head->_next=del->_next;del_node(del);}}void DisplayLink(node *head){assert(head);node *cur=head->_next;while(cur){ printf("%d ",cur->_data); cur=cur->_next;}printf("\n");}void DestroyLink(node *head){int data=0;assert(head);while(!IsEmpty(head)){ PopFront(head,&data);} free(head); head=NULL;}void testLink(){node *head=NULL;InitLink(&head);int i=0;int data=0;for(;i<10;++i){ PushFront(head,i); DisplayLink(head);}for(i=0;i<10;++i){ PopFront(head,&data);DisplayLink(head);}DestroyLink(head);}void *product_run(void *arg){int data=0;node *head=(node *)arg;while(1){usleep(1234567);data=rand()%1000;
//pthread_mutex_lock(&mylock);//加锁PushFront(head,data);//pthread_mutex_unlock(&mylock);//解锁pthread_cond_signal(&mycond);printf("product is done data=%d\n",data);}}void *consumer_run(void *arg){int data=0;node *head=(node *)arg;while(1){//pthread_mutex_lock(&mylock);//加锁while(!IsEmpty(head)){pthread_cond_wait(&mycond,&mylock);}PopFront(head,&data);//pthread_mutex_unlock(&mylock);//解锁printf("consumer is done data=%d\n",data);}}void testMode(){node *head=NULL;InitLink(&head);pthread_t tid1;pthread_t tid2;pthread_create(&tid1,NULL,product_run,(void *)head);pthread_create(&tid2,NULL,consumer_run,(void *)head);pthread_join(tid1,NULL);pthread_join(tid2,NULL);DestroyLink(head);pthread_mutex_destroy(&mylock);pthread_cond_destroy(&mycond);}int main(){testLink();testMode();return 0;}
运行结果:
1.未加锁前:(此时消费未完,便有生产)
2.加锁后(生产一个,消费一个)
之前的图稍微有点问题(本人不小心上传错图了,还请大家多多包涵!),现已改正!
到此结束,谢谢!
- 生产者-消费者问题
- 生产者-消费者问题
- 生产者-消费者问题
- 操作系统:生产者-消费者问题
- 生产者与消费者问题
- 生产者-消费者问题
- 关于生产者-消费者问题
- java生产者 消费者问题
- 消费者和生产者问题
- 生产者消费者问题
- 生产者消费者问题--多线程
- 生产者-消费者同步问题
- 生产者消费者问题
- 生产者与消费者问题
- 生产者 消费者问题!
- 生产者与消费者问题
- 生产者消费者问题
- 关于生产者-消费者问题
- 微信小程序,不可不知的一二三四
- 第三方开源库:流式布局:FlowLayout
- 开源PLM软件Aras详解七 在Aras的Method中如何引用外部DLL
- .cpp调用.c的变量或函数【转】
- 如何判断两个可移动磁盘卷是否在同一个USB HUB上?
- 生产者消费者问题
- Java算法基础之快速排序算法
- ubuntu 14.04 安装虚拟机12.1.0
- 《平凡的世界》读感
- CSS中包含块
- ReactNative自定义控件之 RefreshLayout
- poj 2533 Longest Ordered Subsequence (最长不下降子序列)
- JavaScript的一些基本知识
- 条件语句