生产者消费者问题

来源:互联网 发布: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.加锁后(生产一个,消费一个)


     之前的图稍微有点问题(本人不小心上传错图了,还请大家多多包涵!),现已改正!

到此结束,谢谢!

   

1 1