生产者与消费者模型

生产者与消费者模型

模型:生产者与消费者模型由消费者,生产者以及交易场所构成。

两个线程同时访问一块临界区域的时候,一个进程往这块区域中写数据,另一个进程在里面读数据。被访问的这块临界区域通常叫缓冲区,而往这块缓冲区里写数据的叫生产者,在这块缓冲区里读数据的叫消费者。

遵循的原则: 要实现消费者与生产者的关系,要满足一个原则,就是“321“原则。 3代表的是有三个关系、2代表的是两种角色、1就是一个交易场所。

3种关系:“消费者——消费者,生产者——生产者,消费者——生产者”关系。

其中生产者与生产者存在互斥关系、消费者与消费者之间存在互斥关系、生产者与消费者之间存在同步与互斥关系。

2个角色:“生产者,消费者”。

1个交易场所:“缓冲区”

基于单链表的生产者与消费者模型

互斥锁:如果生产者往缓冲区里生产了一部分数据时,消费者就来直接读取了,那么消费者读到的数据和生产者生产的数据其实不是一个,也就是说生产者与消费者之间没有互斥的制约,为了保证读取到的数据的完整性,必须引入互斥机制,即互斥锁。

int pthread_mutex_lock(pthread_mutex_t *mutex);//上锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁

互斥有两种等待方式,非阻塞时等待(pthread_mutex_lock),和阻塞时等待(pthread_mutex_trylock),解锁为(pthread_mutex_destroy)

int pthread_cond_timedwait(pthread_cond_t *restrict cond,
              pthread_mutex_t *restrict mutex,
              const struct timespec *restrict abstime);//由time控制的等待
int pthread_cond_wait(pthread_cond_t *restrict cond,
              pthread_mutex_t *restrict mutex);//阻塞式等待

当生产者的生产速度特别慢时,而消费者的读取速度特别快,这时当消费者把缓冲区里的数据读完时,生产者还没有生产出相应的数据,那么消费者就要在这里申请互斥锁来继续访问这块缓冲区,为了让消费者在读到缓冲区里没数据的时候,就挂起等待,因此引入一个概念就是条件变量。

条件变量:

条件变量是用来判断生产者与消费者是否满足同步性的。条件变量使我们可以睡眠等待某种条件出现。
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待”条件变量的条件成立”而挂起;另一个线程使”条件成立”(给出条件成立信号)。相当于消费者在等待生产者的时候,当生产者生产出来数据以后, 通过条件变量的信号去通知消费者,然后消费者被唤醒继续消费。
为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。条件变量类型为pthread_cond_t。

测试用例:

由一个单向链表实现消费模型:在一个单链表里用(单)生产者与(单)消费者模型来模拟生产、消费情景。

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

pthread_mutex_t mutex_lock=PTHREAD_MUTEX_INITIALIZER;//init lock
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;//init cond   

ypedef struct SeqList
{
     int data;
     struct SeqList* next;
}SeqList;

SeqList* list=NULL;

SeqList* Buynode(int d)
{
    SeqList* list=(SeqList*)malloc(sizeof(SeqList));
    list->data=d;
    list->next=NULL;
    return list;
}
void PushFront(SeqList **pplist,int d)
{
     SeqList* tmp=Buynode(d);
     tmp->next=*pplist;
     *pplist=tmp;
}

int PopFront(SeqList** pplist)
{
    if(*pplist==NULL)
    {
        return ;
    }
    SeqList* tmp=(*pplist)->next;
    int ret=(*pplist)->data;
    free(*pplist);
    *pplist=tmp;
    return ret;
 }

 void *product(void *arg)
 {
     while(1)
 {
     int d=rand()/9527;
     int i=pthread_mutex_lock(&mutex_lock);//申请锁
     if(i!=0)
     {
         pthread_cond_wait(&cond,&mutex_lock);
     }
     PushFront(&list,d);
     printf("product %d\n",d);
     pthread_mutex_unlock(&mutex_lock);//释放锁
     sleep(1);
     }
}

void *consume(void *arg)
{
    while(1)
    {
        sleep(1);
        int i=pthread_mutex_lock(&mutex_lock);
        int ret=PopFront(&list);
        if(i!=0)
        {
            pthread_cond_wait(&cond,&mutex_lock);
        }
        printf("consume %d\n",ret);
        pthread_mutex_unlock(&mutex_lock);
    }
}

int main()
{
     pthread_t t_a;
     pthread_t t_b;
     pthread_create(&t_a,NULL,product,(void*)NULL);
     pthread_create(&t_b,NULL,consume,(void*)NULL);
     pthread_join(t_b,NULL);
     pthread_mutex_destroy(&mutex_lock);
     pthread_cond_destroy(&cond);
     return 0;
}

基于环形队列的生产者与消费者模型

这里写图片描述
格子数信号量由c通知p,消费后,格子为空,可写入。
数据信号量由p通知c,生产后,格子有数据,可读取。

实现条件

  1. p不能超过c一圈。除了开始位置,c和p不能相遇,如果p写满数据来到c后面时只能等c拿走数据后再写入。
  2. c永远跟在p后面。p没有写数据时,c不能读取数据。

    测试用例

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

int arr[SIZE]={0};
int ret = 0;
sem_t datasem;
sem_t blanksem;

void *product(void *arg)
{
    int i=0;
    while(1)
    {
        sem_wait(&blanksem);
        arr[ret]=i;
        printf("product done! %d\n", arr[ret]);
        sem_post(&datasem);
        i++;
        ret++;
        ret %= SIZE;
     }
}

void *consume(void *arg)
{
    while(1)
    {
        sem_wait(&datasem);
        printf("consume done! %d\n", arr[ret]);
        sem_post(&blanksem);
        sleep(1);
    }
}

int main()
{
    pthread_t c;
    pthread_t p;
    sem_init(&datasem, 0, 0);
    sem_init(&blanksem,0, SIZE);
    pthread_create(&p, NULL, product, NULL);
    pthread_create(&c, NULL, consume, NULL);
    pthread_join(c, NULL);
    pthread_join(p, NULL);
    sem_destroy(&datasem);
    sem_destroy(&blanksem);
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值