Linux系统下实现生产者消费者问题

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

        假定在生产者和消费者之间的公用缓冲池中具有n个缓冲区,这时可利用互斥信号量mutex实现诸进程对缓冲池的互斥使用:利用信号量empty和full分别表示缓冲池中空缓冲区和满缓冲区的数量。又假定这些生产者和消费者相互等效,只要缓冲池未满,生产者便可将消息送入缓冲池;只要缓冲池未空,消费者便可从缓冲池中取走一个消息。PV原语算法如下所示:

 实现代码如下:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#define BUFSIZE 10
#define PRODUCER_NUM 3
#define CONSUMER_NUM 3
sem_t full;
sem_t empty;
sem_t mutex;
//定义缓冲区
int buf[BUFSIZE];
//队尾
int in = 0;
//队头
int out = 0;

void printbuf()
{
    for(int i=0; i<BUFSIZE; i++)
    {
        printf("%d", buf[i]);
    }
    printf("\n");
}

//生产者线程处理函数
void* producer(void* arg)
{
    int number_p = *((int *)arg);
    while(1)
    {
        sem_wait(&empty);
        sem_wait(&mutex);
        buf[in] = 1;
        printf("生产者%d生产产品:%d  buf:", number_p, in);
        printbuf();
        in = (in + 1)%BUFSIZE;
        sem_post(&full);
        sem_post(&mutex);
        sleep(rand()%3);
    }


    return NULL;
}
//消费者线程处理函数
void* consumer(void* arg)
{
    int number_c = *((int *)arg);
    while(1)
    {
        sem_wait(&full);
        sem_wait(&mutex);
        buf[out] = 0;
        printf("消费者%d消费产品:%d  buf:", number_c, out);
        printbuf();
        out = (out + 1)%BUFSIZE;
        sem_post(&empty);
        sem_post(&mutex);
        sleep(rand()%3);
    }

    return NULL;
}


int main()
{
    
    pthread_t tid[PRODUCER_NUM+CONSUMER_NUM];
    //创建三个信号量
    sem_init(&full, 0, 0);
    sem_init(&empty, 0, BUFSIZE);
    sem_init(&mutex, 0, 1);
    int* number = malloc(sizeof(int) * (PRODUCER_NUM+CONSUMER_NUM));

    for(int i=0; i<PRODUCER_NUM+CONSUMER_NUM; i++)
    {
        if(i < PRODUCER_NUM)
        {
            //创建生产者线程
            number[i] = i;
            pthread_create(&tid[i], NULL, producer, (void *)(number+i));
        }
        else
        {
            //创建消费者线程
            number[i] = i-PRODUCER_NUM;
            pthread_create(&tid[i], NULL, consumer, (void *)(number+i));
        }

    }
    //回收线程
    for(int i=0; i<PRODUCER_NUM+CONSUMER_NUM; i++)
    {
        pthread_join(tid[i], NULL);
    }
    //销毁信号量
    sem_destroy(&full);
    sem_destroy(&empty);
    sem_destroy(&mutex);
    free(number);

    return 0;
}

主要使用的函数接口是信号量的初始化和销毁,以及P和V操作,定义如下:

int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:
    创建一个信号量并初始化它的值。一个无名信号量在被使用前必须先初始化。
参数:
    sem:信号量的地址。
    pshared:等于 0,信号量在线程间共享(常用);不等于0,信号量在进程间共享。
    value:信号量的初始值。
返回值:
    成功:0
    失败: - 1

int sem_destroy(sem_t *sem);
功能:
    删除 sem 标识的信号量。
参数:
    sem:信号量地址。
返回值:
    成功:0
    失败: - 1

int sem_wait(sem_t *sem);
功能:
    将信号量的值减 1。操作前,先检查信号量(sem)的值是否为 0,若信号量为 0,此函数会阻塞,直到信号量大于 0 时才进行减 1 操作。
参数:
    sem:信号量的地址。
返回值:
    成功:0
    失败: - 1

int sem_post(sem_t *sem);
功能:
    将信号量的值加 1 并发出信号唤醒等待线程(sem_wait())。
参数:
    sem:信号量的地址。
返回值:
    成功:0
    失败:-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值