本文主要来总结生产者-消费者模型的代码实现,至于其原理,请大家自行百度.

一、基于链表的生产-消费模型(条件变量)

我们以链表为例,生产者进行头部插入,消费者进行头部删除,因此,先将链表相关操作封装为LinkList.h,具体代码如下:

////////////////////////////////////
//文件说明: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");
}

然后进入我们线程的生产消费模型:

////////////////////////////////////
//文件说明: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;
}

二、基于环形队列的生产-消费模型(信号量)

////////////////////////////////////
//文件说明: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;
}