生产者消费者模型

1.基本概念

    生产者和消费这模型也称为有界缓冲区问题.两个进程共享一个公共的固定大小的缓冲区. 其中一个进程是生产者, 负责专门往缓冲区中放数据,而另外一个进程是消费者, 负责专门从缓冲区中取数据. 问题在于解决当缓冲区已满的时候,此时当生产者还想继续往缓冲区中放数据, 当缓冲区空的时候, 消费者想要从缓冲取中取数据. 为了解决该问题,我们利用信号量来解决生产者和消费者问题.
    现在为了方便起见, 我们利用信号量的一个简化版本, 互斥量,来解决生产者,消费者问题.互斥量是一个可以处于加锁和解锁状态的变量. 因此我们可以用一个二进制位来表示该互斥量的状态, 用 0 表示解锁, 用1表示加锁. 当一个线程要访问临界区的时候, 调用 mutex_lock 如果该互斥量是解锁的,调用成功, 如果该互斥量是加锁的, 那么就阻塞.

2. pthread中的互斥量

    当一个线程想要进入临界区, 它首先要先尝试锁住相关的互斥量,如果互斥量没有加锁, 那么该线程就可以立即进入临界区, 如果该互斥量被锁定, 则该线程将会被阻塞, 直到该互斥量被解锁.

3.条件变量

    回到我们的生产者消费者模型上来.生产者将产品放入缓冲取,消费者从缓冲区中取数据. 如果生产者发现缓冲取已满, 此时已经没有位置去放产品的时候, 它就得阻塞起来,直到有消费者将缓冲区中的产品取出. 生产者可以调用互斥量进行原子检测, 而不受影响. 同时生产者发现缓冲区已满的时候, 此时生产者就得在阻塞自己的同时, 确保自己在某个时候可以被唤醒. 这就是条件标量所做的事了.条件变量通常是和互斥量一起使用. 这种模式用于让一个线程将互斥量锁住, 当它不能在获得它期待的结果时等待的一个条件变量. 最后,另一个线程会向它发信号, 使它可以继续执行. 同时需要注意, 条件变量不存在与内存中, 如果将一个信号量传递给一个没有线程等待的条件变量, 那么该信号将会被丢弃

4. 代码演示
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include<semaphore.h>

#define BUFSIZE 10
#define CONSUMER_COUNT 1
#define PRODUCER_COUNT 1
sem_t full;
sem_t empty;
pthread_mutex_t mutex;
int in = 0;
int out = 0;
int g_buff[BUFSIZE];
int prodeuce_id = 0;
pthread_t g_thread[CONSUMER_COUNT + PRODUCER_COUNT];

void* consume(void* p)
{
    int num = *(int*)p;
    free(p);
    int i = 0;
    while(1)
    {
        printf("%d wait buff not empty\n");
        sem_wait(&full);
        pthread_mutex_lock(&mutex);
        for(; i < BUFSIZE; i++)
        {
            printf("%02d ", i);
            if(g_buff[i] == -1)
            {
                printf("null");
            }
            else
            {
                printf("%d", g_buff[i]);
            }
            if(i == out)
            {
                printf("\t<--consumer");
            }
            printf("\n");
        }
        printf("%d begin consume a product %d\n");
        g_buff[ out ] = -1;
        out = (out + 1) % BUFSIZE;
        printf("%d end consume a product %d\n", num, prodeuce_id);
        pthread_mutex_unlock(&mutex);
        sem_post(&empty);
        sleep(1);
    }
    //P(full)
    //拿数据
    //V(empty)
}

void* produce(void* p)
{
    int num = *(int*)p;
    free(p);
    int i = 0;
    //P(empty)
    //生产数据
    //V(full)
    while(1)
    {
        printf("%d wait buffer not full\n");
        sem_wait(&empty);
        pthread_mutex_lock(&mutex);
        for(; i < BUFSIZE; i++)
        {
            printf("%02d ", i);
            if(g_buff[i] == -1)
            {
                printf("null");
            }
            else
            {
                printf("%d", g_buff[i]);
            }
            if(i == in)
            {
                printf("\t<--produce");
            }
            printf("\n");
        }
       printf("%d begin produce a product %d\n", num ,prodeuce_id);
       g_buff[ in ] = prodeuce_id;
       in = (in + 1) % BUFSIZE;
       printf("%d end produce a product %d\n", num, prodeuce_id++);
       pthread_mutex_unlock(&mutex);
       sem_post(&full);
       sleep(5);
    }

}
int main()
{
    int i = 0;
    for(; i < BUFSIZE; i++)
    {
        g_buff[i] = -1;
    }

    sem_init(&full, 0, BUFSIZE);
    sem_init(&empty, 0, 0);
    pthread_mutex_init(&mutex, NULL);
    pthread_t consumer;
    pthread_t producer;

    for(i = 0; i < PRODUCER_COUNT; i++)
    {
        int* p = (int*)malloc(sizeof(int));
        *p = i;
        pthread_create(g_thread + i, NULL, produce, (void*)p);
    }

    for(i = 0; i < CONSUMER_COUNT; i++)
    {
        int* p = (int*)malloc(sizeof(int));
        *p = i;
        pthread_create(g_thread + i, NULL, consume, (void*)p);
    }

    for(i = 0; i < PRODUCER_COUNT + CONSUMER_COUNT; i++)
    {
        pthread_join(g_thread[i], NULL);
    }

    pthread_mutex_destroy(&mutex);
    sem_destroy(&full);
    sem_destroy(&empty);
    return 0;
}

                                  这里写图片描述
    本次先实现但消费者单生产者模型, 后继会写出多生产者, 多消费者模型.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值