生产者消费者问题

                                生产者消费者问题

1.生产者消费者简单程序
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#define MAX_STOCK 20//仓库容量
char g_storage[MAX_STOCK];
size_t g_stock=0;//当前库存
//互斥量
pthread_mutex_t g_mtx=PTHREAD_MUTEX_INITIALIZER;
//条件变量
pthread_cond_t g_full=PTHREAD_COND_INITIALIZER;//满仓   条件变量
pthread_cond_t g_empty=PTHREAD_COND_INITIALIZER;//空仓
//显示库存
void show(const char*who,const char*op,char prod)
{
    printf("%s:",who);
    size_t i;
    for(i=0;i<g_stock;++i)
      printf("%c",g_storage[i]);
    printf("%s%c\n",op,prod);
}
//生产者线程
void *producer(void*arg)
{
    const char *who=(const char*)arg;
    for(;;)
    {
    pthread_mutex_lock (&g_mtx);
    if(g_stock>=MAX_STOCK)
    {
        printf("%s:满仓\n",who);
        pthread_cond_wait(&g_full,&g_mtx);//wait->解锁(消费者可以加锁)-》给full变量加锁-》
  //这个时候wait要能结束挂起状态需要两个条件1full值解锁了2互斥锁被打开了-》
        //pthread_cond_signal(&g_full);pthread_mutex_unlock(&g_mtx);只有这两个都运行了,以上条件才能满足
  //这样wait才能结束挂起(判断条件变量并加上互斥锁)
    }  
        char prod='A'+rand()%26;
        show(who,"<-",prod);
        g_storage[g_stock++]=prod;
        pthread_cond_signal(&g_empty);
        pthread_mutex_unlock(&g_mtx);
        usleep((rand()%100)*1000);
    }
    return NULL;
}
//消费者线程
void*customer(void*arg)
{
//  usleep(10000);
    const char*who=(const char*)arg;
    for(;;)
    {
        pthread_mutex_lock(&g_mtx);
        if(!g_stock)
        {
            printf("%s:空仓!\n",who);
            pthread_cond_wait(&g_empty,&g_mtx);
        }
      char prod=g_storage[--g_stock];
    show(who,"->",prod);
    pthread_cond_signal(&g_full);//即使没有等待的线程也返回成功
    pthread_mutex_unlock(&g_mtx);
    usleep((rand()%100)*1000);
    }
    return NULL;
}
int main(){
    srand(time(NULL));
    pthread_attr_t attr;//线程属性,这个结构体可以设置很多与线程运行有关的属性。
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//设置线程分离策略,主线程不用等待子线程结束。不用等pthread_join返回。
    pthread_t tid1;
    pthread_t tid2;
    pthread_create(&tid1,&attr,producer,"生产者");
    pthread_create(&tid2,&attr,customer,"消费者");
    getchar();
return 0;
}


2.说明:
**pthread_cond_wait 执行的流程首先将这个mutex解锁, 然后等待条件变量被唤醒, 如果没有被唤醒, 该线程将一直休眠, 也就是说, 该线程将一直阻塞在
这个pthread_cond_wait调用中, 而当此线程被唤醒时, 将自动将这个mutex加锁,然后再进行条件变量判断(原因是“惊群效应”,如果是多个线程都在等待
这个条件,而同时只能有一个线程进行处理,此时就必须要再次条件判断,以使只有一个线程进入临界区处理。),如果满足,则线程继续执行,最后解锁,
也就是说pthread_cond_wait实际上可以看作是以下几个动作的合体:
1.解锁线程锁
2.等待线程唤醒,并且条件为true加锁线程锁.
**pthread_cond_signal仅仅负责唤醒正在阻塞在同一条件变量上的一个线程,如果存在多个线程,系统自动根据调度策略决定唤醒其中的一个线程,在多处理
器上,该函数是可能同时唤醒多个线程,同时该函数与锁操作无关,解锁是由pthread_mutex_unlock(&mutex)完成
**唤醒丢失问题 
在线程并没有阻塞在条件变量上时,调用pthread_cond_signal或pthread_cond_broadcast函数可能会引起唤醒丢失问题。
唤醒丢失往往会在下面的情况下发生:
一个线程调用pthread_cond_signal或pthread_cond_broadcast函数; 
另一个线程正处在测试条件变量和调用pthread_cond_wait函数之间; 
没有线程正在处在阻塞等待的状态下。

3.小结:

生产者消费者之间是通过互斥量和条件变量的结合来完成的(本例没有用多个生产者消费者)。我们的互斥量(锁)以及线程的信号量是用来控制同步也就是临界资源只能由一个线程去使用。但是生产消费关系比同步要稍复杂一点,它不仅要考虑到同步更要考虑到临界资源是否可以生产或者消费这就必须要使用条件变量,在临街资源不能为进来的资源提供服务的情况下及时释放进来这个线程拿到的锁以保证不会产生死锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值