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; } |