【操作系统】生产者消费者问题实现

news/2024/11/7 19:31:09/

目录

实验原理:

实验内容:

实验器材(设备、元器件):

实验步骤:

实验数据及结果分析:


  • 实验原理:

考虑n个缓冲区的缓冲池作为一个共享资源,当生产者进程从数据源—文件中读取数据后将会申请一个缓冲区,并将此数据放入缓冲区中。消费者从一个缓冲区中取走数据,并将其中的内容打印输出。当生产者进程正在访问缓冲区时,消费者进程不能同时访问缓冲区,因此缓冲区是个互斥资源。

生产者、消费者程序执行流程如下图所示:

            

工程实践证明,利用信号量方法实现进程互斥是高效的,一直被广泛采用,通过信号量机制实现生产者、消费者问题,可以通过以下步骤实现。

步骤1:分配具有n个缓冲区的缓冲池,作为共享资源。

步骤2:定义两个资源型信号量empty 和full,empty信号量表示当前空的缓冲区数量,full表示当前满的缓冲区数量。

步骤3:定义互斥信号量mutex,当某个进程访问缓冲区之前先获取此信号量,在对缓冲区的操作完成后再释放此互斥信号量。以此实现多个进程对共享资源的互斥访问。

步骤4:创建3进程(或者线程)作为生产者,4个进程(或者线程)作为消费者。创建一个文件作为数据源,文件中事先写入一些内容作为内容。

步骤5 :编写代码实现生产者进程的工作内容,即从文件中读取数据,然后申请一个empty信号量,和互斥信号量,然后进入临界区操作将读取的数据放入此缓冲区中。并释放empty信号量和互斥信号量。

步骤6:编写代码实现消费者者进程的工作内容,即先申请一个full信号量,和互斥信号量,然后进入临界区操作从缓冲区中读取数据并打印输出。

Linux系统可以采用的信号量程序接口包括:

1、POSIX命名信号量:使用POSIX IPC名字标识,可用于进程或者线程间的同步。

2、POSIX内存信号量:存放在共享内存中,可用于进程或者线程间的同步。

3、SYSTEM V信号量:在内核中维护,可用于进程或者线程间的同步。

  • 实验目的:
  1. 掌握进程、线程的概念,熟悉相关的控制语;
  2. 掌握进程、线程间的同步原理和方法;
  3. 掌握进程、线程间的互斥原理和方法。
  • 实验内容:

有一群生产者进程在生产产品,并将这些产品提供给消费者进程去消费。为使生产者进程与消费者进程能并发执行,在两者之间设置了一个具有n个缓冲区的缓冲池:生产者进程从文件中读取一个数据,并将它存放到一个缓冲区中; 消费者进程从一个缓冲区中取走数据,并输出此数据。生产者和消费者之间必须保持同步原则:不允许消费者进程到一个空缓冲区去取产品;也不允许生产者进程向一个已装满产品且尚未被取走的缓冲区中投放产品。

创建3进程(或者线程)作为生产者,4个进程(或者线程)作为消费者。创建一个文件作为数据源,文件中事先写入一些内容作为数据。

生产者和消费者进程(或者线程)都具有相同的优先级。

  • 实验器材(设备、元器件):

PC计算机,操作系统:Ubuntu

  • 实验步骤:

1. 使用XShell连接终端;

2. 使用vim命令打开文本编辑器进行编码:vim prog2.c\

3. 编写数据文件data.txt

4.编译程序:

   gcc prog22.c -o a -lpthread

5. 执行程序:./a

  • 实验数据及结果分析:

实验数据

类型

初始化

mutex信号量

pthread_mutex_t

1

empty_sem

sem_t

M

full_sem

Sem_t

0

生产者循环次数

int

20

消费者循环次数

int

15

通过循环消费者生产者问题,没有发现报错,即没有出现死锁,均正常执行。

实验结果:

成功实现了生产者消费者问题。  

代码分析:

消费者函数 consumer():

  1.  void *consumer()
  2.  {
  3.   consumer_id++;
  4.   int id = consumer_id;
  5.   int count = 30;
  6.   while (count)
  7.   {
  8.    count--;
  9.    sleep(1);
  10.    sem_wait(&full_sem);        //如果为空则等待
  11.    pthread_mutex_lock(&mutex); //实现互斥
  12.    out %= M;
  13.    printf("消费者%d%d号缓冲区取出一个数据:%d\n"idout, buff[out]);
  14.    buff[out] = 0;
  15.    out++;
  16.    pthread_mutex_unlock(&mutex);
  17.    sem_post(&empty_sem);
  18.   }
  19.  }

实现:等待full信号量,加锁,产品取出缓冲区,解锁操作,并在加锁不成功时进行阻塞操作,

通过out%=M实现数组内循环;

生产者函数 producer():

  1. /*生产者方法*/
  2.  void *producer()
  3.  {
  4.   producer_id++;
  5.   int id = producer_id;
  6.   int count = 40;
  7.   while (count)
  8.   {
  9.    count--;
  10.    sleep(1);
  11.    sem_wait(&empty_sem);
  12.    pthread_mutex_lock(&mutex); //实现互斥
  13.    if (fscanf(fp, "%d", &data) == EOF)
  14.    {
  15.     fseek(fp, 0, SEEK_SET);
  16.     fscanf(fp, "%d", &data);
  17.    }
  18.    in %= M;
  19.    buff[in] = data;
  20.    printf("生产者%d%d号缓冲区放入了一个数据:%d\n", id, in, buff[in]);
  21.    in++;
  22.    pthread_mutex_unlock(&mutex);
  23.    sem_post(&full_sem);
  24.   }
  25.  }

通过fscanf和fseek实现从文件中读取数据。等待empty信号量,加锁,产品放入缓冲区,解锁操作,并在加锁不成功时进行阻塞操作。

主函数main():

  1. int main()
  2.  {
  3.   pthread_t id1[producer_Num]; //声明生产者线程的ID数组
  4.   pthread_t id2[consumer_Num]; //声明消费者现车组的ID数组
  5.   int ret1[producer_Num];
  6.   int ret2[consumer_Num];
  7.   int ini1 = sem_init(&empty_sem, 0, M); //缓冲区当前有M个空位
  8.   int ini2 = sem_init(&full_sem, 00);  //缓冲区当前有0个可用
  9.   int int3 = pthread_mutex_init(&mutex, NULL);
  10.   fp = fopen("./data.txt""r"); //打开当前目录下data.txt文件,只读
  11.   if (fp == NULL)
  12.   {
  13.    exit(1); //异常
  14.   }
  15.   //创建生产者线程
  16.   for (int i = 0; i < producer_Num; i++)
  17.   {
  18.    ret1[i] = pthread_create(&id1[i], NULL, producer, NULL);
  19.   }
  20.   //创建消费者线程
  21.   for (int i = 0; i < consumer_Num; i++)
  22.   {
  23.    ret2[i] = pthread_create(&id2[i], NULL, consumer, NULL);
  24.   }
  25.   //销毁线程
  26.   for (int i = 0; i < producer_Num; i++)
  27.   {
  28.    pthread_join(id1[i], NULL);
  29.   }
  30.   //创建消费者线程
  31.   for (int i = 0; i < consumer_Num; i++)
  32.   {
  33.    pthread_join(id2[i], NULL);
  34.   }
  35.   exit(0);
  36.  }

主函数实现了信号量的初始化以及打开文件操作,并创建生产者消费者任务。


http://www.ppmy.cn/news/497984.html

相关文章

基于开路电压+安时积分法估算锂电池SOC

上一章节有说到开路电压校准的SOC初始值&#xff0c;本章介绍怎么利用这个SOC初始值在电池处于动态时&#xff0c;通过安时积分法去估算实时的SOC。 安时积分法即通过采集的电流&#xff0c;实时累积AH&#xff0c;通过累积的AH容量去估算当前的SOC值。笔者是通过采用模拟前端B…

代码生成 | 安时积分法模型搭建

安时积分法是电池电量计量最基础的方法&#xff0c;今天我们用simulink建模的方式做一个安时积分模型&#xff0c;从而更好地理解安时积分的思想也掌握建模的基础操 ​新建文件 打开MATLAB启动simulink新建一个模型文件 定义变量 和手写代码一样&#xff0c;先定义几个后面…

BMS-SOC算法——安时积分法

安时积分法是一种电池电量计量的基础方法&#xff0c;它采用AH累积的方法&#xff0c;对动态的锂电池进行实时的SOC估算。安时积分法的计算公式如下&#xff1a; SOC(t)SOC0​CE1​∫0t​I(τ)dτ 其中&#xff0c;SOC0​是电池电荷状态的初始电量值&#xff1b;CE是电池的额…

基于开路电压+安时积分法估算锂电池SOC(一)

SOC对于电池的寿命以及使用效率是至关重要的&#xff0c;对于锂电池的SOC估算&#xff0c;有很多种&#xff0c;开路电压、安时积分、卡尔曼滤波、神经网络等方法。卡尔曼滤波、神经网络训练这两种方法目前只是处于理论阶段&#xff0c;对于开发人员开发难度大。安时积分法、开…

10安时、12安时和14安时是什么意思啊?

安时指的是电池的容量&#xff0c;通俗的说就是电池稳定放电的能力。一般来说&#xff0c;电动车在运行时&#xff0c;放电的电流大约是5安培。电动车的运行里程是这样计算的。就是电池的安时数除以5安培&#xff0c;再乘以电动车标明的运行的速度&#xff0c;大约是24公里&…

ARL资产侦察灯塔系统搭建及使用

ARL资产侦察灯塔系统搭建及使用 1.ARL简介2.ARL搭建2.ARL使用1.ARL简介 ARL资产侦察灯塔系统旨在快速侦察与目标关联的互联网资产,构建基础资产信息库。协助甲方安全团队或者渗透测试人员有效侦察和检索资产,发现存在的薄弱点和攻击面 资产梳理的路径会根据输入的数据进行变动…

封神之后,又来超神?南卡OE骨传导开放式耳机有啥新本领

终于到了适合夜跑的温度&#xff0c;我的新跑鞋和专用陪跑运动耳机也都收到了&#xff0c;万事俱备却意外中招“二阳”了。虽然身体情况&#xff0c;短期是不能支持去跑步运动了&#xff0c;但每天戴着新耳机打打王者也还是一样很欢乐的。 反正现在时间很多很闲&#xff0c;我…

车辆派遣管理系统——需求

文章目录 一、背景二、用户的特点三、系统范围四、系统体系结构系统总体架构描述&#xff1a; 五、数据库设计E-R图数据字典 六、工作量估算七、项目燃尽图 一、背景 车辆派遣管理系统是提供对车辆派遣高效管理的系统&#xff0c;自动生成结算结果&#xff1b;可以有效节约车辆…