Linux多线程之生产者消费者问题(条件变量)

linux多线程之生产者消费者问题

什么叫做生产者消费者问题?

生产者消费者问题,也称有限缓冲问题,是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据

解决方法

要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有信号量法等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形

开发流程图示:
在这里插入图片描述

生产者:	                            	    消费者:
1. mutex_lock()加锁	                        1. mutex_lock()加锁
2. while 循环判断库存                        2. while 循环库存判断
   已满(真):cond_wait()等待	               已空(真):cond_wait()等待
   未满(假):循环结束                          未空(假):循环结束
3. 生产产品                                  3. 消费产品
4. if 判断消费条件(库存为1)是否满足          4. if 判断生产条件(库存为最大库存-1)是否满足
   满足:signal()/broadcast()广播               满足:signal()/broadcase()广播            
5. mutex_unlock()解锁	                    5. mutex_unlock()解锁
6. 选择性使用sleep()暂停生产,让出CPU 	    6. 选择性使用sleep()暂停消费,让出CPU

为何不使用 if 判断库存,而使用 while 循环判断库存?
生产者:当库存已满,调用cond_wait()等待,某时刻接收到条件满足信号,
       立即去加锁,但是锁被其他生产者拿走了,待其他生产者生产完产品释放锁,       
       随后竞争到锁时库存变为满状态,此时就应该重新判断库存状态。
       这里使用 while 循环就能实现cond_wait()前后都进行库存判断的效果。	
消费者:当库存已空,调用cond_wait()等待,某时刻接收到条件满足信号,
       立即去加锁,但是锁被其他消费者拿走了,待其他消费者消费完产品释放锁,       
       随后竞争到锁时库存变为空状态,此时就应该重新判断库存状态。
       这里使用 while 循环就能实现cond_wait()前后都进行库存判断的效果。     

实现

产品通过链表方式存储源码查看:https://gitee.com/oneGotoOne/linuxLearn/blob/master/11/demo.c

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

#define maxProductNumber 5

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condPro = PTHREAD_COND_INITIALIZER;
pthread_cond_t condCon = PTHREAD_COND_INITIALIZER;

typedef struct msg {
	int pro_array[maxProductNumber];
	int size;
} stor;
stor product;

void *producer(void *arg) 
{
	while (1) {
		pthread_mutex_lock(&mutex);
		
		while(product.size == maxProductNumber) {
			pthread_cond_wait(&condPro, &mutex);
		}
		
		product.pro_array[product.size] = (rand() % 200) + 1;
		product.size++;
		printf("%lu:produce a product:%d	Total products:%d\n", \
	 		pthread_self(), product.pro_array[product.size - 1], product.size);
		
		if (product.size == 1) {
			pthread_cond_signal(&condCon);
		}
		
		pthread_mutex_unlock(&mutex);
		sleep(rand()%5);
	}
	
	pthread_exit(NULL);
}

void *consumer(void *arg)
{
	while (1) {
		pthread_mutex_lock(&mutex);
		
		while (product.size == 0) {
			pthread_cond_wait(&condCon, &mutex);
		}
		
		printf("%lu:consume a product:%d	Total products:%d\n", \
            pthread_self(), product.pro_array[product.size], --product.size);
			
		if (product.size == maxProductNumber -1) {
			pthread_cond_signal(&condPro);
		}
		
		pthread_mutex_unlock(&mutex);
		sleep(rand()%5);
	}

	pthread_exit(NULL);
}

int main()
{
	int ret = 0;
	pthread_t producerID;
	pthread_t consumerID;

	product.size = 0;
	srand(time(NULL));
	ret = pthread_create(&producerID, NULL, producer, NULL); 
	if (ret != 0) {
		fprintf(stderr, "pthread_create:producer error  ret:%s \n", strerror(ret));
		exit(-1);
	}
	ret = pthread_create(&consumerID, NULL, consumer, NULL);
	if (ret != 0) {
		fprintf(stderr, "pthread_create:consumer error  ret:%s \n", strerror(ret));
		exit(-1);
	}

	pthread_join(producerID, NULL);
	pthread_join(consumerID, NULL);
	pthread_mutex_destroy(&mutex);
	pthread_cond_destroy(&condCon);
	pthread_cond_destroy(&condPro);

	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值