Linux下生产者与消费者模型

1. 概念
  有一个或多个生产者生产某种类型的数据,并放在缓冲区里(生产者),有一个消费者从缓冲区中取数据,每次取一项(消费者)。系统保证任何时候只有一个主题可以访问缓存区。所以当生产满时,生产者不会再生产数据;当缓冲区为空时,消费者不会从中移走数据。 接下来解释同步和互斥的概念,然后用代码(链表、环形队列)模拟生产者与消费者的关系。
  互斥与同步:假设两个或者更多的进程需要访问一个不可共享的资源,如打印机。在执行过程中,每个进程都给该I/O设备发命令,接收状态信息,收发数据。我们把这类资源叫做临界资源,使用临界资源的那一部分程序叫做程序的临界区。而一次只允许一个程序在临界区,即实现原子性(原子性为对外不可分)访问。而使它门有序的进行访问为同步
2. 生产者与消费者模型
  生产者与生产者之间为互斥关系,消费者与消费者之间为互斥,生产者与消费者之间为为同步、互斥。关系图为:


1) 使用链表模拟
  我们采用链表的头插和头删来模拟生产数据和消费数据这两个过程。大致流程如下:

代码如下:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>

typedef struct List
{
    int _data;
    struct List* _next;
}List,*pList;

pList getNode(int d)
{
    pList node = (pList)malloc(sizeof(List));
    if(node == NULL)
    {
        perror("malloc");
        exit(1);
    }
    node->_data = d;
    node->_next = NULL;
    return node;
}

void pushFront(int d, pList* pplist)
{
    pList node=  getNode(d);
    if(*pplist == NULL)
        *pplist = node;
    else
    {   
        node->_next = *pplist;
        *pplist = node;
    }
}

void  popFront(pList* pplist, int *data)
{
    pList cur = *pplist;
    if(cur == NULL)
    {
        exit(1);
    }
    while(cur->_next == NULL)
    {
       *data = cur->_data;
        free(cur);
        cur == NULL;
        exit(2);
    }
    *pplist = cur->_next;
    *data = cur->_data;
    free(cur);
}

int isEmpty(pList l)
{
    if(l == NULL)
    {
        return 1;
    }
    return 0;
}

void desList(pList* pplist)
{
    pList cur = *pplist;
    pList del = NULL;
    while(cur != NULL)
    {
        del = cur;
        cur = cur->_next;
        free(del);
        del = NULL;
    }
    *pplist = NULL;
}

//静态方式创建,赋予常量
pthread_cond_t mycond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
pList list = NULL;

void* consume(void* arg)
{
    int data = 0;
    while(1)
    {
        sleep(2);
        //阻塞式加锁
        pthread_mutex_lock(&mylock);
        while(isEmpty(list))
        {
            //条件不满足时,进入阻塞式等待
            pthread_cond_wait(&mycond, &mylock);
        }
        popFront(&list,&data);
        printf("consume get : %d\n",data);
        //解锁
        pthread_mutex_unlock(&mylock);
    }
}

void* product( void* arg)
{
    int data = 0;
    while(1)
    {
        pthread_mutex_lock(&mylock);
        data = rand()%100;
        pushFront(data,&list);
        printf("product put : %d\n",data);
        pthread_mutex_unlock(&mylock);
        //激活一个等待该条件的线程
        pthread_cond_signal(&mycond);
        sleep(1);
    }
}

int main()
{
    pthread_t tid1,tid2;
    //线程的创建与等待
    pthread_create(&tid1, NULL, consume, NULL);
    pthread_create(&tid2, NULL, product, NULL);
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    desList(&list);

    pthread_mutex_destroy(&mylock);
    //没有线程在该条件变量上等待的时候注销这个条件
    //变量,否则返回EBUSY
    pthread_cond_destroy(&mycond);
    return 0;
}

2)环形队列实现
实现流程如下:


代码如下:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <semaphore.h>
#define SIZE 4

int stor[SIZE];
//创建信号量
sem_t blankSem;
sem_t dataSem;

void* consumer()
{
    int step = 0;
    int data = 0;
    while(1)
    {
        sleep(1);
        //等待数据信号量
        sem_wait(&dataSem);
        data = stor[step++];
        //释放空格信号量
        sem_post(&blankSem);
        step %= SIZE;
        printf("consumer get: %d\n",data);
    }
}
void* producter()
{
    int step = 0;
    int data = 0;
    while(1)
    {
        sem_wait(&blankSem);
        stor[step++] = data++;
        sem_post(&dataSem);
        step %= SIZE;
        printf("producter put: %d\n",data);
    }
}
int main()
{
    //初始化信号量,格子SIZE个,数据0个
    sem_init(&blankSem, 0, SIZE);
    sem_init(&dataSem, 0, 0);
    pthread_t td1,td2;
    //创建和等待线程
    pthread_create(&td1, NULL, consumer, NULL);
    pthread_create(&td2, NULL, producter, NULL);
    pthread_join(td1, NULL);
    pthread_join(td2, NULL);
    //销毁信号量
    sem_destroy(&blankSem);
    sem_destroy(&dataSem);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值