生产者消费者问题概述:
多个线程同时从一块缓冲区中读取数据,并且有一个或者多个线程同时向这块缓冲区中写入数据。
读取(取走)数据的线程成为“消费者”
写入(添加)数据的线程称为“生产者”
生产者消费者模型的优点:
①解耦
生产者和消费者的代码发生变化都不会对对方产生影响,变成生产者、缓冲区、消费者这种低耦合的
②支持并发
生产者产生的数据添加到缓冲区,就可以再去产生下一个数据了,消费者也是一样,从缓冲区中读取数据之后无需等待生产者。可以使得生产者和消费者并发执行
③支持忙闲不均
生产者只需要负责向缓冲区中添加数据,如果缓冲区的数据已经存放满了,就不添加。消费者只是负责从缓冲区中读取数据,当缓冲区空了,就不读取数据了,使得生产者和消费者的处理能力达到动态平衡。
流程图:
上述流程图中用到了两个信号量和一个互斥锁,下面对信号量的个数以及使用互斥锁的原因作以说明:
之所以使用两个信号量原因在于:由生产者和消费者两个线程,生产者这个线程能够执行的条件是缓冲区中的数据必须不满,要有空余的空间继续存放数据,消费者这个线程能够执行的条件是缓冲区必须要有数据可以读取,不为空,所以应该使用两个信号量来进行控制,从而保证什么时候生产者线程能够向缓冲区中写入数据,什么时候消费者能够从缓冲区中读取数据。
之所以用到互斥锁原因在于:生产者有多个,不能让多个生产者同时向缓冲区中写入数据。同理,消费者也有多个,也不能让多个消费者同时从缓冲区中读取数据。所以对于buff的操作,还需要通过互斥锁来进行控制。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#define BUFF_SIZE 10//定义缓冲区的大小为10
#define SC_NUM 2//生产的个数为2
#define XF_NUM 3//消费者的个数为3
sem_t sem_empty;
sem_t sem_full;
pthread_mutex_t mutex;
int in=0;//当前写缓冲区
int out=0;//当前读缓冲区
int buff[BUFF_SIZE]={0};
//生产者的线程
void* Sc_thread(void* arg)
{
int index=(int)arg;
for(int i=0;i<30;i++)
{
sem_wait(&sem_empty);//p操作-1,Buff的空余空间减少一个
pthread_mutex_lock(&mutex);//加锁,当前生产者在进行生产,其他生产者不能进行操作
buff[in]=rand()%100;
printf("生产者%d,生产数据%d,in=%d\n",index,buff[in],in);
in=(in+1)%BUFF_SIZE;
pthread_mutex_unlock(&mutex);//解锁,当前生产者生产结束,其他生产者可以进行生产了
sem_post(&sem_full);//v操作+1,Buff的填充空间又多了一个有效数据等待生产者读取
int n=rand()%10;
sleep(n);
}
}
//消费者的线程
void* Xf_thread(void* arg)
{
int index=(int)arg;
for(int i=0;i<20;i++)
{
sem_wait(&sem_full);
pthread_mutex_lock(&mutex);
printf("消费者%d,消费数据%d,out=%d\n",index,buff[out],out);
out=(out+1)%BUFF_SIZE;
pthread_mutex_unlock(&mutex);
sem_post(&sem_empty);
int n=rand()%10;
sleep(n);
}
}
int main()
{
pthread_mutex_init(&mutex,NULL);
sem_init(&sem_empty,0,BUFF_SIZE);
sem_init(&sem_full,0,0);
srand((int)time(NULL));
pthread_t Sc_id[SC_NUM];
pthread_t Xf_id[XF_NUM];
//创建线程
for(int i=0;i<SC_NUM;i++)
{
pthread_create(&Sc_id[i],NULL,Sc_thread,(void*)i);
}
for(int i=0;i<XF_NUM;i++)
{
pthread_create(&Xf_id[i],NULL,Xf_thread,(void*)i);
}
//等待线程结束
for(int i=0;i<SC_NUM;i++)
{
pthread_join(Sc_id[i],NULL);
}
for(int i=0;i<XF_NUM;i++)
{
pthread_join(Xf_id[i],NULL);
}
//销毁信号量
sem_destroy(&sem_empty);
sem_destroy(&sem_full);
//销毁互斥锁
pthread_mutex_destroy(&mutex);
exit(0);
}
程序运行结果: