https://www.cnblogs.com/caolicangzhu/p/7086176.html
本文主要来总结生产者-消费者模型的代码实现,至于其原理,请大家自行百度.
一、基于链表的生产-消费模型(条件变量)
我们以链表为例,生产者进行头部插入,消费者进行头部删除,因此,先将链表相关操作封装为LinkList.h,具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | //文件说明:LinkList.h//作者:高小调//创建时间:2017年06月27日 星期二 14时57分27秒//开发环境:Kali Linux/g++ v6.3.0#include<assert.h>#include<stdlib.h>#include<stdio.h>//链表节点typedef struct LinkListNode{ int val; struct inkListNode *next;}Node,*pNode,**ppNode;//初始化链表void InitLinkList(ppNode head){ assert(head); *head = NULL;}//判断链表是否为空int IsEmpty(pNode head){ return head==NULL;}//申请新节点pNode BuyNewNode(int val){ pNode ret = (pNode)malloc(sizeof(Node)); ret->val = val; ret->next = NULL; return ret;}//头插void PushFront(ppNode head,int val){ assert(head); if(*head==NULL){ *head = BuyNewNode(val); return ; } pNode newNode = BuyNewNode(val); newNode->next = *head; *head = newNode;}//头删void PopFront(ppNode head,int *val){ assert(head); if((*head) == NULL){ return ; } if((*head)->next == NULL){ *val = (*head)->val; free(*head); *head = NULL; return ; } pNode del = *head; *head = del->next; *val = del->val; free(del);}//销毁链表void Destory(ppNode head){ assert(head); pNode cur = *head; pNode del = NULL; while(cur!=NULL){ del = cur; cur = cur->next; free(del); } *head = NULL;}//打印链表void PrintLinkList(pNode head){ pNode cur = head; while(cur!=NULL){ printf("%d ",cur->val); cur = cur->next; } printf("\n");} |
然后进入我们线程的生产消费模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | //文件说明:test.c//作者:高小调//创建时间:2017年06月27日 星期二 14时56分13秒//开发环境:Kali Linux/g++ v6.3.0#include<stdio.h>#include<pthread.h>#include"LinkList.h"//互斥锁pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;//条件变量pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//测试链表void TestLinkList(){ pNode head; InitLinkList(&head); int tmp; for(int i=0; i<10; ++i){ PushFront(&head,i); PrintLinkList(head); } for(int i=0; i<10; ++i){ PopFront(&head,&tmp); PrintLinkList(head); }}pNode head;//生产者:每次向头节点插入数据void *Productor(void*arg){ int val = 0; while(1){ //互斥锁加锁:确保生产时不会消费,消费时不会生产 pthread_mutex_lock(&lock); val = rand()%100; PushFront(&head,val); printf("Productor push %d\n",val); //互斥锁解锁 pthread_mutex_unlock(&lock); //条件变量,生产完成之后向消费者发出信号消费 pthread_cond_signal(&cond); sleep(1); }}//消费者:每次将头节点数据取出void *Consumer(void*arg){ int val = 0; while(1){ //互斥锁 pthread_mutex_lock(&lock); while(head==NULL){ //链表中没数据,阻塞等待生产者发消费信号 printf("wait for data\n"); pthread_cond_wait(&cond,&lock); } PopFront(&head,&val); printf("Consumer pop %d\n",val); pthread_mutex_unlock(&lock); sleep(1); }}int main(){ InitLinkList(&head); pthread_t cid1,cid2; pthread_create(&cid1,NULL,Productor,NULL); pthread_create(&cid2,NULL,Consumer,NULL); pthread_join(&cid1,NULL); pthread_join(&cid2,NULL); return 0;} |
二、基于环形队列的生产-消费模型(信号量)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | //文件说明:test2.c//作者:高小调//创建时间:2017年06月27日 星期二 16时29分30秒//开发环境:Kali Linux/g++ v6.3.0#include<stdio.h>#include<pthread.h>#include<semaphore.h>#include<stdlib.h>#define SIZE 1024//环形队列int arr[SIZE] = {0};sem_t sem_pro; //描述环形队列中的空位置sem_t sem_con; //描述唤醒队列中的数据//生产者,只要环形队列有空位,便不断生产void*productor(void*arg){ int data = 0; int proIndex = 0; while(1){ //有空位便生产,没空位便阻塞等消费者消费 sem_wait(&sem_pro); data = rand()%1234; arr[proIndex] = data; printf("product done %d\n",data); proIndex = (proIndex+1)%SIZE; //供消费者消费的数据加1 sem_post(&sem_con); }}//消费者,只要环形队列中有数据,就不断消费void*consumer(void*arg){ int data = 0; int conIndex = 0; while(1){ //环形队列中存在数据则消费,不存在数据则阻塞,直到有数据为止 sem_wait(&sem_con); data = arr[conIndex]; printf("consume done %d\n",data); conIndex = (conIndex+1)%SIZE; //最后,消费了一个数据,空位加1 sem_post(&sem_pro); }}int main(){ pthread_t pro,con; sem_init(&sem_pro,0,SIZE-1); //一开始有很多空位置 sem_init(&sem_con,0,0); //但并没有数据 pthread_create(&pro,NULL,productor,NULL); pthread_create(&con,NULL,consumer,NULL); pthread_join(pro,NULL); pthread_join(con,NULL); sem_destroy(&sem_pro); sem_destroy(&sem_con); return 0;} |