生产者消费者模型

生产者消费者模型是一个多线程同步问题的经典案例。
这里写图片描述
从上图简单来看A,B,C为生产者D,E为消费者,生产者呢把数据放入缓冲区,而消费者呢从缓冲区拿走数据。生产者与生产者,消费者与消费者之间呢是互斥的,生产者与消费者呢又是同步的。
简单分析下生产者消费者模型的好处:
生产者与消费者两个‘’种族‘’间的耦合度降低,也就是说生产者是否生产取决于缓存是否满,消费者消费取决于缓存是否空。大家呢是独立的,生产者呢不必每次生产豆看消费者是否消费,消费者每次消费不必等待生产者是否生产结束。大家的运行都取决于缓存这个中间媒介。

下面就简单来看下生产者消费者模型的具体实现。
1.信号量配合互斥锁实现
先简单的认识下信号量,我们对信号量有两种操作,wait(等待)和release(释放),当一个线程调用wait操作时,它要么得到资源然后将信号量减1,要么一直阻塞下去,直到信号量大于等于1是,也就是消费者想要消费必须有资源,不能透支,release(释放)对信号量加1。二者对应的操作如下。

int sem_wait(sem_t * sem);
int sem_post(sem_t * sem);
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
#include<stdlib.h>

#define MAX 6

pthread_mutex_t mutex;
int nready;
sem_t full;  //放入数据的个数
sem_t empty; //有多少剩余空间

void* produce( void* arg )
{
    int i = *(int*)arg;
    while( 1 )
    {
        sem_wait(&empty);  //需要有足够的空间
        pthread_mutex_lock(&mutex); 

        printf("process %d is begin produce\n",i);
        sleep(2);
        nready++;
        printf("process %d is end produce nready(%d)\n",i,nready);

        pthread_mutex_unlock(&mutex);
        sem_post(&full);  //将放入数据个数+1
        sleep(3);
    }
}

void* custom( void* arg )
{
    int i = *(int*)arg;
    while( 1 )
    {
        sem_wait(&full);  //要有数据
        pthread_mutex_lock(&mutex);

        printf("process %d is begin custom\n",i);
        sleep(1);
        --nready;
        printf("process %d is end custom nready(%d)\n",i,nready);

        pthread_mutex_unlock(&mutex);
        sem_post(&empty); //让空间+1
        sleep(1);
    }
}

int main()
{
    pthread_mutex_init(&mutex,NULL);
    sem_init(&full,0,0);
    sem_init(&empty,0,MAX);

    pthread_t prs[2];
    pthread_t cus[3];

    int i;
    for( i=0; i<2; i++ )
    {
        int* p = (int*)malloc(sizeof(int));
        *p = i;
        pthread_create(&prs[i],NULL,produce,(void*)p);
    }
    for( i=0; i<3; i++ )
    {
        int* p = (int*)malloc(sizeof(int));
        *p = i;
        pthread_create(&cus[i],NULL,custom,(void*)p);
    }

    for( i=0; i<3; i++ )
        pthread_join(prs[i],NULL);
    for( i=0; i<2; i++ )
        pthread_join(cus[i],NULL);


    pthread_mutex_destroy(&mutex);
}

试想一下,如果把sem_wait()和sem_post()放到pthread_mutex_lock()pthread_mutex_unlock()之间会如何呢?
答案是死锁,因为我们不能预知线程进入共享区顺序,如果消费者线程先对mutex加锁,并进入,sem_wait()发现队列为空,阻塞,而生产者在对mutex加锁时,发现已上锁也阻塞,双方永远无法唤醒对方。

2.条件变量加互斥锁`

pthread_mutex_lock(&mutex);

while( 条件为假 ) //担心wait被信号打断
pthread_cond_wait( &cond,&mutex );
修改条件
pthread_mutex_unclock(&mutex);

让条件满足的代码
pthread_mutex_lock(&mutex);
将条件设置成真
pthread_cond_signal( &cond );
//signal发送信息,如果没有wait,就会丢失。
pthread_mutex_unclock(&mutex);

为什么信号量在互斥区外,而条件变量在互斥区内呢?

因为互斥锁本质上是二元信号量,和信号量互斥的原理相同,而且放在互斥区会死锁,而条件变量是和互斥锁协同配合的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值