信号量--------多线程下的生产者消费者模型

更多linux知识点:linux目录索引


1. 生产者消费者模型

  从现实生活中的角度出发,对于这个模型,我们可以总结为3 2 1原则,即:

  1. 三种关系:

    • 生产者与生产者:互斥关系,我生产的时候你不能生产
    • 消费者与消费者:互斥关系,我消费的时候你不能消费
    • 生产者与消费者:同步关系,我生产了你才能消费,我消费完了你才能生产
  2. 两个角色

    • 生产者
    • 消费者
  3. 一个中间媒介
    • 生产出来的产品

2. 使用规范

  在这里是基于多线程的生产者消费者模型,势必会出现多个线程同时生产,多个线程同时消费,生产者没有生产完,消费者就去消费等的情况,此时为了解决这些问题,我们引入互斥量、条件变量、信号量等概念;并且在使用时遵循以下的规则:
 
  这里写图片描述

3. 信号量

  关于互斥锁和条件变量在这里不详细介绍,今天主要用到信号量,前面进程间通信时也用到过进程间通信—信号量,进程间的信是以集合的形式出现,而这里我们实现线程间的互斥所用的信号量是以个数的形式出现,而且实现要比进程间通信的信号量简单的多。

4. 函数接口

  1. sem_init———-初始化信号量

         #include <semaphore.h>
         int sem_init(sem_t *sem, int pshared, unsigned int value);
    
        //参数:
        //1.sem:表示你要初始化的信号量
        //2.pshared:0表示线程间共享,非0表示进程间共享
        //3.value:信号量的初始值
    
  2. sem_destory———销毁信号量

        #include <semaphore.h>
        int sem_destroy(sem_t *sem);
        //参数:创建的信号量
  3. sem_wait———–等待信号量(p操作)

        #include <semaphore.h>
        int sem_post(sem_t *sem);
        //p操作,将信号量值减一,相当于减资源
    
  4. sem_post———-发布信号量(V操作)

        #include <semaphore.h>
        int sem_wait(sem_t *sem);
        //v操作,表示使用完资源了,可以将其归还

5. 基于环形队列的生产者消费者模型

  5.1 思路:

  1. 队列一般是用链表来实现,但是链表存储不是连续的,在这里使用数组实现环形队列,长度为n
  2. 对于生产者,实际操作的是数组中空位置的个数,范围是:n—->0
  3. 对于消费者,实际操作的是数组中数据的个数,范围是:0—–>n
  4. 当生产者和消费者指向同一个位置,就可能出现死锁的问题,故此我们遵循3个原则
    1. 生产者要先与消费者
    2. 当环形队列为空,必须保证生产者先运行(为空或则满由计数器决定)
    3. 当环形队列为满时,必须保证消费者先运行

代码:

#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
#include <sys/types.h>

#include <stdlib.h>
#include <string.h>

#define N 64

int buff[N];//环形队列

sem_t blanks;//生产者
sem_t datas;//消费者

pthread_mutex_t mutex;//实现互斥



void* procduct(void* arg)
{

    int i = 0;
    while(1){
        printf("Procduct start pocduct\n");

        sem_wait(&blanks);//拿走一个资源
        pthread_mutex_lock(&mutex);//一次只允许一个生产者

        int data = rand()%2048;
        buff[i] = data;
        printf("pocuduct data is: %d\n",data);
        ++i;
        i = i%N;
        pthread_mutex_unlock(&mutex);//生产完毕,解锁,让其他生产者进行生产
        sem_post(&datas);//生产完毕,数据个数加1
        sleep(1);
    }

}


void* consumer(void* arg)
{

    int i = 0;
    while(1){
        printf("consumer start consum\n");

        sem_wait(&datas);
        pthread_mutex_lock(&mutex);//保证一个消费者进行消费

        int data = buff[i];
        printf("consumer data is: %d\n",data);
        ++i;
        i = i%N;

        sem_post(&blanks);
        pthread_mutex_unlock(&mutex);

        //sleep(1);
    }
}
int main()
{
    srand(time(0));
    //初始化信号量
    sem_init(&blanks, 0, N);//生产者的信号量,n--> 0
    sem_init(&datas, 0, 0);//消费者的信号量,0---> n


    pthread_mutex_init(&mutex, NULL);//互斥锁的出初始化
    //创建两个生产者,两个消费者

    pthread_t pid1,pid2;//生产者
    pthread_t cid1,cid2;//消费者


    pthread_create(&pid1, NULL, procduct, NULL);
    pthread_create(&pid2, NULL, procduct, NULL);


    pthread_create(&cid1, NULL, consumer, NULL);
    pthread_create(&cid1, NULL, consumer, NULL);



    sem_destroy(&blanks);
    sem_destroy(&datas);

    pthread_mutex_destroy(&mutex);

    pthread_join(pid1,NULL);
    pthread_join(pid2,NULL);



    pthread_join(cid1,NULL);
    pthread_join(cid2,NULL);


    return 0;
}

结果:

这里写图片描述

这里写图片描述

猜你喜欢

转载自blog.csdn.net/zhangye3017/article/details/80711813