消费者/生产者问题

OS实验-消费者/生产者问题(含代码实现)

问题描述

​ 有一群生产者进程(线程)在生产产品,并将这些产品提供给消费者进程(线程)去消费。为使生产者进程(线程)与消费者进程(线程)能并发执行,在两者之间设置了一个具有n个缓冲区的缓冲池:生产者进程(线程)将它所生产的产品放入一个缓冲区中;消费者进程(线程)可从一个缓冲区中取走产品去消费。

​ 它们之间必须保持同步原则:不允许消费者进程(线程)到一个空缓冲区去取产品;也不允许生产者进程(线程)向一个已装满产品且尚未被取走的缓冲区中投放产品。

​ 本篇博客以线程的方式来实现

实现方式

用一个数组来表示上述的具有n个(0,1,…,n-1)缓冲区的缓冲池,设置两个指针:

指针in:指示下一个可投放产品的缓冲区,每当生产者进程生产并投放一个产品后,in指针加1,即in∶=(in+1)mod n

指针out:指示下一个可从中获取产品的缓冲区,每当消费者进程取走一个产品后,out指针加1,即out∶=(out+1) mod n

当**(in+1) mod n=out时表示缓冲池满**;而in=out则表示缓冲池空

但是如果直接使用这种方式,在并发执行时,就会出现差错(资源的竞争),因此此处引入互斥量mutex来解决互斥问题。

需要引入的头文件

stdio.h
stdlib.h
time.h ——> 用于产生随机数
pthread.h ——> 包含线程的创建等函数
semaphore.h ——> 用于信号量的设定

需要用到的函数

函数声明作用
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);用于创建一个线程
int pthread_join(pthread_t thread,void rval_ptr);父线程等待子线程终止
sem_init(sem_t *sem, int pshared, unsigned int value);初始化一个信号量
sem_post(sem_t *sem);信号量P操作,信号量值加1;若有线程阻塞于信号量sem,则调度器会唤醒对应阻塞队列中的某一个线程
sem_wait(sem_t *sem);信号量V操作,若信号量值小于0,则线程阻塞于信号量sem,直到sem大于0;否则信号量值减1

具体函数的使用请见代码实现部分:

代码实现

/**
	************************************************************
	************************************************************
	*	作者: 		曾彬芮
	* 
	*	日期: 		2021-4-5
	*
	*	版本: 		V1.0
	*
	*	说明: 		消费者/生产者问题的实现
	************************************************************
	************************************************************
**/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <semaphore.h>

#define CRITICAL_SECTION_NUM 10
#define PRODUCER_NUM 3
#define CUSTOMER_NUM 4


int CriticalSection[CRITICAL_SECTION_NUM] = {0};
sem_t empty; sem_t full; sem_t mutex;

int in = 0;
int out = 0;

void *PutData();
void *GetData();

void *PutData(){
    while(1){
        sem_wait(&empty);
        sem_wait(&mutex);
        CriticalSection[in] = rand()%9 + 1;  // 产生一个1-9的随机数放入临界区
        printf("I am producer and I put %d in\n",CriticalSection[in]);
        in = (in+1)%(CRITICAL_SECTION_NUM);
        sem_post(&mutex);
        sem_post(&full);
    }
}

void *GetData()
{
    while(1){
        sem_wait(&full);
        sem_wait(&mutex);
        printf("I am customer and I take %d out\n",CriticalSection[out]);
        CriticalSection[out] = 0;
        out = (out+1)%(CRITICAL_SECTION_NUM);
        sem_post(&mutex);
        sem_post(&empty);
    }
}


int main()
{
    sem_init(&empty, 0, CRITICAL_SECTION_NUM);  // 使用sem_init函数进行初始化
    sem_init(&full, 0, 0);
    sem_init(&mutex, 0, 1);

    pthread_t PRO1, PRO2, PRO3;       // 三个生产者
    pthread_t CUS1, CUS2, CUS3, CUS4; // 四个消费者

    srand((unsigned)time(NULL));      // 用于产生随机数

    pthread_create(&PRO1, NULL, PutData, NULL);   // 以下创建三个生产者(线程)与四个消费者(线程)
    pthread_create(&PRO2, NULL, PutData, NULL);
    pthread_create(&PRO3, NULL, PutData, NULL);
    pthread_create(&CUS1, NULL, GetData, NULL);
    pthread_create(&CUS2, NULL, GetData, NULL);
    pthread_create(&CUS3, NULL, GetData, NULL);
    pthread_create(&CUS4, NULL, GetData, NULL);

    pthread_join(PRO1, NULL);  // 父线程等待子线程终止
    pthread_join(PRO2, NULL);
    pthread_join(PRO3, NULL);
    pthread_join(CUS1, NULL);
    pthread_join(CUS2, NULL);
    pthread_join(CUS3, NULL);
    pthread_join(CUS4, NULL);

    return 0;
}

代码完成后在Linux终端使用命令 gcc -o ### ###.c -lpthread编译,再输入 ./### 运行即可(###表示文件名)。
以上代码均为自己编写,并已在Linux虚拟机下成功编译运行,若仍有问题还劳烦各位读者朋友指正!

注:创建线程时需要在gcc最后加上“-lpthread”,否则会报错。

2021.4.6 于 电子科技大学(沙河校区)

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值