一、概念
生产者:产生数据的的模块。
消费者:处理数据的模块。
那么生产者产生数据之后,消费者怎么拿,从哪拿呢?所以,仅仅有这两个角色是不能完成我们期望的工作的。还需要一个缓冲区,就像超市的货架一样,供货商(生产者)将商品摆到货架(缓冲区)上,购买者(消费者)从货架上拿走,这个货架也是必不可少的。
试想如果没有缓冲区,生产者生产一个数据之后,就必须等待消费者消费完成,生产者才能继续生产,那么如果生产者很快,而消费者很慢,那么就只能让生产者干等。这就好比让CPU和外设直接打交道,如果没有缓存,还不得慢死,白白浪费CPU时间。
抽象出此模型如下:
接下来说明三种关系:
1.生产者与生产者之间:就像供货商与供货商之间,存在明显的竞争关系,在操作系统上,我们称为互斥关系。
2.消费者与消费者之间:同样是互斥的。
3.生产者与消费者之间:首先必须保证,生产者在生产时,消费者不能来打扰,否则会出现数据二义性的问题。(生产者要往缓冲区里写入“1234”,刚写了12时消费者就来缓冲区取数据了,那么它拿到的只能是12)。同时,消费者在消费时生产者也不能打扰,道理是一样的。所以,它们之间也有互斥的关系。除了互斥外,还必须保证生产者消费者按照一定的顺序访问资源。因为必须是让生产者先生产,消费者才能进行消费,类似于这样按照顺序访问资源成为同步,所以这两者之间还有同步的关系。
二、模型模拟
1.一个生产者一个消费者。
我们使用两个线程分别模拟生产者和消费者,使用单链表作为缓冲区,每次让生产者PUSH数据到链表头,消费者也每次从链表头部取POP数据。
完整的代码:
#include<stdio.h> #include<pthread.h> #include<stdlib.h> #include<unistd.h> #include<assert.h> pthread_mutex_t mylock=PTHREAD_MUTEX_INITIALIZER; pthread_cond_t mycond=PTHREAD_COND_INITIALIZER; typedef struct node { int _data; struct node* _next; }node,*pnode; typedef struct Linklist { node * phead; }Linklist,*pLinklist; pnode creatNode(int data) { pnode newnode=(pnode)malloc(sizeof(node)); if(newnode==NULL) { perror("malloc"); exit(EXIT_FAILURE); } newnode->_data=data; newnode->_next=NULL; return newnode; } void initList(pLinklist plist) { assert(plist); //pLinklist head=(pLinklist)malloc(sizeof(Linklist)); // plist=head; plist->phead=NULL; } void pushHead(pLinklist list,int data) { assert(list); pnode newnode=creatNode(data); if(list->phead==NULL) { list->phead=newnode; return; } newnode->_next=list->phead; list->phead=newnode; } void popHead(pLinklist list,int* data) { assert(list); if(list->phead==NULL) { printf("list empty!\n"); return; } pnode del=list->phead; *data=del->_data; list->phead=del->_next; del->_next=NULL; free(del); } void destoryList(pLinklist list) { assert(list); if(list->phead!=NULL) { pnode cur =list->phead; while(cur) { pnode del=cur; cur=cur->_next; free(del); del=NULL; } } list->phead=NULL; } void showList(pLinklist list) { assert(list); pnode cur=list->phead; while(cur!=NULL) { printf("%d ",cur->_data); cur=cur->_next; } printf("\n"); } void* producter_thread(void* arg) { pLinklist list=(pLinklist)arg; while(1) { sleep(1); pthread_mutex_lock(&mylock); //访问临界区前加锁 pushHead(list,rand()%1000); pthread_cond_signal(&mycond); //生产完毕唤醒等待在该条件变量下的线程 pthread_mutex_unlock(&mylock); //访问结束解锁 printf("producter success %d\n",list->phead->_data); } } void* consumer_thread(void* arg) { pLinklist list=(pLinklist)arg; while(1) { sleep(1); pthread_mutex_lock(&mylock); //加锁 int data=0; while(list->phead==NULL) { pthread_cond_wait(&mycond,&mylock); //若链表中无数据,则消费者需要等待。 } popHead(list,&data); pthread_mutex_unlock(&mylock); //解锁 printf("consumer success %d\n",data); } } int main() { Linklist list; initList(&list); pthread_t tid1,tid2; pthread_create(&tid1,NULL,producter_thread,(void*)&list);//创建线程 pthread_create(&tid2,NULL,consumer_thread,(void*)&list); pthread_join(tid1,NULL); //等待线程结束回收线程 pthread_join(tid2,NULL); destoryList(&list); return 0; } |