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

在linxu的多线程机制中,由于可能同时对临界资源进行读写操作,因此互斥锁经常被用来进行互斥操作。

初次之外信号量和环形队列等互斥机制则使用起来更为简单。

一、基于环形队列的生产-消费模型(信号量)

////////////////////////////////////
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
#include<stdlib.h>
#define SIZE 1024
//环形队列
int arr[SIZE] = {0};
sem_t sem_pro;      //描述环形队列中的空位置
sem_t sem_con;      //描述唤醒队列中的数据
//生产者,只要环形队列有空位,便不断生产
void*productor(void*arg){
    int data = 0;
    int proIndex = 0;
    while(1){
        //有空位便生产,没空位便阻塞等消费者消费
        sem_wait(&sem_pro);
        data = rand()%1234;
        arr[proIndex] = data;
        printf("product done %d\n",data);
        proIndex = (proIndex+1)%SIZE;
        //供消费者消费的数据加1
        sem_post(&sem_con);
    }
}
//消费者,只要环形队列中有数据,就不断消费
void*consumer(void*arg){
    int data = 0;
    int conIndex = 0;
    while(1){
        //环形队列中存在数据则消费,不存在数据则阻塞,直到有数据为止
        sem_wait(&sem_con);
        data = arr[conIndex];
        printf("consume done %d\n",data);
        conIndex = (conIndex+1)%SIZE;
        //最后,消费了一个数据,空位加1
        sem_post(&sem_pro);
    }
}
 
int main(){
    pthread_t pro,con;
    sem_init(&sem_pro,0,SIZE-1);        //一开始有很多空位置
    sem_init(&sem_con,0,0);         //但并没有数据
 
    pthread_create(&pro,NULL,productor,NULL);
    pthread_create(&con,NULL,consumer,NULL);
    pthread_join(pro,NULL);
    pthread_join(con,NULL); //这里为了演示,更好的是设置线程 分离pthread_detach(con)
 sem_destroy(&sem_pro); sem_destroy(&sem_con); return 0;} 
 
 
 

二、环形队列

       队列具有天然的互斥特性,被广泛地应用到linux内核 和python中,可以创建工作队列。另一篇博客  管道的环形设计方法

有详细的介绍。

1. 环形队列

在队列为空时,生产者必须先运行,消费者不能越过生产者
在队列为满时,消费者先运行,生产者不能超过消费者一圈,
不能同时访问同一位置:
  • 1
  • 2
  • 3
  • 4

2. 信号量

    sem_t sem;//POSIX的线程标准下的
    信号量机制通过信号量的值控制可用资源的数量。线程访问共享资源前,需要申请获取一个信号量,如果信号量为0,说明当前无可用的资源,线程无法获取信号量,则该线程会等待其他资源释放信号量(信号量加1)。如果信号量不为0,说明当前有可用的资源,此时线程占用一个资源,对应信号量减1。
    举例:
    停车场有5个停车位,汽车可使用停车位。在这里5个停车位是共享的资源,汽车是线程。开始信号量为5,表明此时有5个停车位可用。一辆汽车进入停车场前,先查询信号量的值,不为0表明有可用停车位,汽车进入停车场并使用一个停车位,信号量减1,表明占用一个停车位,可用数减少。
    信号量初始化函数:
    int sem_init(sem_t *sem, int pshared, unsigned int value);
    sem: 信号量
    pshared:参数表示这个信号量是否在进程的线程之间共享进程之间
    value:初始值 
    nt sem_wait(sem_t *sem);
    该函数申请一个信号量,当前无可用信号量则等待,有可用信号量时占用一个信号量,对信号量的值减1。
    信号量加1:
    int sem_post(sem_t *sem);
    该函数释放一个信号量,信号量的值加1。
    销毁信号量:
    int sem_destory(sem_t *sem);
    该函数销毁信号量。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
    sem_init(&blankSem, 0, SIZE);//初始化
    sem_init(&dataSem, 0, 0);
  • 1
  • 2

3.临界资源

创建全局数组 int ring[SIZE] = 0;
  • 1
  • 2

这里写图片描述
这样信号量不仅可以实现生产者与消费者的同步,而且可以实现互斥(两者不可能同时访问同一资源);

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

void* product(void *arg)//生产者
{
    int i = 0;
    int n = 0;
    while(1)
    {
        sem_wait(&blankSem);//申请格子放数据
        ring[i] = n++;//减一成功后,放数据
        sem_post(&dataSem);//数据放完成后,数据数目加1,
        printf("product doing! %d\n",ring[i++]);

        i = i%SIZE;
    }
    return NULL;
}
void* consume(void *arg) //消费者
{
    int i = 0;
    int data = 0;
    while(1)
    {   sem_wait(&dataSem);//请求拿数据,阻塞方式
        data = ring[i]; //
        sem_post(&blankSem);//拿到数据后,空格加1
        printf("consume doing %d\n",data);
        sleep(1);
        i++;
        i = i%SIZE;//实现环形
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

2. 基于环形队列的多生产者多消费者模型编写。

信号量只能实现生产者与消费者之间的·互斥·同步·
现在多生产者和消费者,所以需要加入,互斥锁实现生产者与生产者之间的互斥,消费者与消费者之间的互斥;
  • 1
  • 2
  • 3
int i = 0int n = 0;
int data = 0; 
void* product_1(void *arg)//生产者1
{
    while(1)
    {
        pthread_mutex_lock(&lock_2); 
        //信号量在生产者之间是临界资源,所以在互斥锁加解之间
        sem_wait(&blankSem);//申请放数据
        ring[i] = n++;
        sem_post(&dataSem);//放完数据,增加数据数目
        printf("product_1 doing! %d\n",ring[i++]);      
        i = i%SIZE;
        pthread_mutex_unlock(&lock_2);//解锁
        sleep(1);
    }
    return NULL;
}
void* product_2(void *arg)//生产者2
{
    while(1)
    {
        pthread_mutex_lock(&lock_2);//解锁
        sem_wait(&blankSem);
        ring[i] = n++;
        sem_post(&dataSem);
        printf("product_2 doing! %d\n",ring[i++]);      
        i = i%SIZE;
        pthread_mutex_unlock(&lock_2);
        sleep(1);
    }
    return NULL;
}
void* consume_1(void *arg)//消费者1
{
    int data = 0;
    while(1)
    {
        pthread_mutex_lock(&lock_1);//解锁
        sem_wait(&dataSem);//申请拿数据
        data = ring[con]; 
        sem_post(&blankSem);//拿数据后,增加空格数目
        printf("consume_1 doing %d\n",data);
        sleep(1);
        con++;
        con = con%SIZE;
        pthread_mutex_unlock(&lock_1);//解锁
        sleep(2);
    }
    return NULL;
}
void* consume_2(void *arg)//消费者2
{
    int data = 0;
    while(1)
    {
        pthread_mutex_lock(&lock_1);
        sem_wait(&dataSem);
        data = ring[con]; 
        sem_post(&blankSem);
        printf("consume_2 doing %d\n",data);
        sleep(1);
        con++;
        con = con%SIZE;
        pthread_mutex_unlock(&lock_1);
        sleep(2);
    }
        return NULL;
}

猜你喜欢

转载自blog.csdn.net/runner668/article/details/80316448