Linux——生产者和消费者模型

生产者消费者问题概述:

多个线程同时从一块缓冲区中读取数据,并且有一个或者多个线程同时向这块缓冲区中写入数据。
读取(取走)数据的线程成为“消费者”
写入(添加)数据的线程称为“生产者”

生产者消费者模型的优点:

①解耦
生产者和消费者的代码发生变化都不会对对方产生影响,变成生产者、缓冲区、消费者这种低耦合的
②支持并发
生产者产生的数据添加到缓冲区,就可以再去产生下一个数据了,消费者也是一样,从缓冲区中读取数据之后无需等待生产者。可以使得生产者和消费者并发执行
③支持忙闲不均
生产者只需要负责向缓冲区中添加数据,如果缓冲区的数据已经存放满了,就不添加。消费者只是负责从缓冲区中读取数据,当缓冲区空了,就不读取数据了,使得生产者和消费者的处理能力达到动态平衡。

流程图:

Linux——生产者和消费者模型_第1张图片
上述流程图中用到了两个信号量和一个互斥锁,下面对信号量的个数以及使用互斥锁的原因作以说明:

之所以使用两个信号量原因在于:由生产者和消费者两个线程,生产者这个线程能够执行的条件是缓冲区中的数据必须不满,要有空余的空间继续存放数据,消费者这个线程能够执行的条件是缓冲区必须要有数据可以读取,不为空,所以应该使用两个信号量来进行控制,从而保证什么时候生产者线程能够向缓冲区中写入数据,什么时候消费者能够从缓冲区中读取数据。

之所以用到互斥锁原因在于:生产者有多个,不能让多个生产者同时向缓冲区中写入数据。同理,消费者也有多个,也不能让多个消费者同时从缓冲区中读取数据。所以对于buff的操作,还需要通过互斥锁来进行控制。

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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);

}

程序运行结果:

Linux——生产者和消费者模型_第2张图片

你可能感兴趣的:(Linux,后端,linux,c语言,开发语言)