Linux Day17 生产者消费者

news2024/11/25 5:28:48

一、生产者消费者问题概述

生产者 / 消费者问题,也被称作有限缓冲问题。两个或者更多的线程共享同一个缓冲 区,其中一个或多个线程作为 生产者 会不断地向缓冲区中添加数据,另一个或者多个线程作为 消费者 从缓冲区中取走数据。生产者 / 消费者模型关注的是以下几点:
1. 生产者和消费者必须互斥的使用缓冲区,即生产者添加数据的时候,消费者不能取走数据,同样消费者在取走数据的时候,生产者不能添加数据。
2.缓冲区空时,消费者不能读取数据
3.缓冲区满时,生产者不能添加数据

二、生产者消费者模型优点:

1. 解耦:因为多了一个缓冲区,所以生产者和消费者并不直接相互调用,这样生产者和消费者的代码 发生变化,都不会对对方产生影响。这样其实就是把生产者和消费者之间的强耦合解开,变成了生 产者和缓冲区,消费者和缓冲区之间的弱耦合
2. 支持并发:如果消费者直接从生产者拿数据,则消费者需要等待生产者生产数据,同样生产者需等待消费者消费数据。而有了生产者 / 消费者模型,生产者和消费者可以是两个独立的并发主体。 生产者把制造出来的数据添加到缓冲区,就可以再去生产下一个数据了。而消费者也是一样的,从
缓冲区中读取数据,不需要等待生产者。这样,生产者和消费者就可以并发的执行。
3. 支持忙闲不均:如果消费者直接从生产者这里拿数据,而生产者生产数据很慢,消费者消费数据很快,或者生产者生产数据很多,消费者消费数据很慢。都会造成占用 CPU 的时间片白白浪费。生产 / 消费者模型中,生产者只需要将生产的数据添加到缓冲区,缓冲区满了就不生产了。消费者从 缓冲区中读取数据,缓冲区空了就不消费了,使得生产者 / 消费者的处理能力达到一个动态的平
衡。

三、生产者消费者模型实现

假定缓冲池中有 N 个缓冲区,一个缓冲区只能存储一个 int 类型的数据。定义互斥锁 mutex 实现对缓
冲区的互斥访问;计数信号量product 用来表示空闲缓冲区的数量,其初值为 N ;计数信号量consume 用来表 示有数据的缓冲区的数量,其初值为 0
一下为画图表示

如图所示,有三个生产者,两个消费者(注意该图所指向仅表示写入数据,并不代表写入同一个空间,读取亦是),设置两个信号量用来控制生产者消费者的运行,首先注意不能先加锁,如果缓冲区满了,此时s1=0,p操作就会阻塞,以至于加锁后无法解锁,所以应该先p操作再加锁,加完锁后就可以开始写入数据,写完后解锁,然后给消费者的信号量+1,这样消费者就可以读取操作了。注意生产者消费者模型并不是生产者将数据生产完后,消费者才能读,是一边生产一边读取。

四、代码实现

根据三的图,我们可以用代码来实现该操作

4.1 信号量+互斥锁

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<semaphore.h>
#include<pthread.h>
#define BUFF_SIZE 10
sem_t product_sem;
sem_t consume_sem;
pthread_mutex_t mutex;
int buff[BUFF_SIZE];
int in=0;
int out=0;

void*pro_fun(void*arg)//生产者
{
    for(int i=0;i<20;i++)
    {
    sem_wait(&product_sem);
    pthread_mutex_lock(&mutex);
    buff[in]=rand()%100;
    printf("生产者在%d处产生数据%d\n",in,buff[in]);
    in=(++in)%10;
    pthread_mutex_unlock(&mutex);
    sem_post(&consume_sem);
    }
}
void*con_fun(void*arg)//消费者
{
    for(int i=0;i<30;i++)
    {
        sem_wait(&consume_sem);
        pthread_mutex_lock(&mutex);
        printf("----------消费者在%d处消费数据%d\n",out,buff[out]);
        out=(++out)%10;
        pthread_mutex_unlock(&mutex);
        sem_post(&product_sem);
    }
}
int main()
{
    sem_init(&product_sem,0,BUFF_SIZE);
    sem_init(&consume_sem,0,0);
    pthread_mutex_init(&mutex,NULL);
    srand((time(NULL)));
    pthread_t pro_id[3];
    for(int i=0;i<3;i++)
    {
         pthread_create(&pro_id[i],NULL,pro_fun,NULL);
    }
    pthread_t con_id[2];
    for(int i=0;i<2;i++)
    {
         pthread_create(&con_id[i],NULL,con_fun,NULL);
    }
    for(int i=0;i<3;i++)
    {
        pthread_join(pro_id[i],NULL);
    }
     for(int i=0;i<2;i++)
    {
        pthread_join(con_id[i],NULL);
    }
    sem_destroy(&product_sem);
    sem_destroy(&consume_sem);
    pthread_mutex_destroy(&mutex);
    exit(0);

}

 

该方法可以精确记录空闲和数据的个数。

4.2 条件变量

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<semaphore.h>
#include<pthread.h>
#define BUFF_SIZE 10

pthread_mutex_t mutex;
pthread_cond_t cond;
int buff[BUFF_SIZE];
int in = 0;
int out = 0;

void* pro_fun(void* arg) {
    for (int i = 0; i < 20; i++) {
        pthread_mutex_lock(&mutex);

        while ((in + 1) % BUFF_SIZE == out) {
            pthread_cond_wait(&cond, &mutex);
        }//如果生产者生产数据值满了,通知消费者

        buff[in] = rand() % 100;
        printf("生产者在%d处产生数据%d\n", in, buff[in]);
        in = (in + 1) % BUFF_SIZE;
        
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

void* con_fun(void* arg) {
    for (int i = 0; i < 30; i++) {
        pthread_mutex_lock(&mutex);
        
        while (in == out) {
            pthread_cond_wait(&cond, &mutex);
        }//如果消费者消费完,通知生产者生产数据
        
        printf("----------消费者在%d处消费数据%d\n", out, buff[out]);
        out = (out + 1) % BUFF_SIZE;
        
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    pthread_cond_init(&cond, NULL);
    pthread_mutex_init(&mutex, NULL);
    srand(time(NULL));

    pthread_t pro_id[3];
    for (int i = 0; i < 3; i++) {
        pthread_create(&pro_id[i], NULL, pro_fun, NULL);
    }

    pthread_t con_id[2];
    for (int i = 0; i < 2; i++) {
        pthread_create(&con_id[i], NULL, con_fun, NULL);
    }
    
    for (int i = 0; i < 3; i++) {
        pthread_join(pro_id[i], NULL);
    }
    for (int i = 0; i < 2; i++) {
        pthread_join(con_id[i], NULL);
    }

    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);

    exit(0);
}

如果对条件变量和信号量不明白的uu可以看一下上几章的内容。后面就要开启网络编程咧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1024213.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

搭建本地MQTT服务器

环境及所用工具 win10本地环境下&#xff0c;使用docker配置一个mqttbroker&#xff0c;选择emqx docker操作&#xff1a;Docker_liangchaaaaa的博客-CSDN博客 测试使用MQTTX软件 Docker拉取镜像仓库 docker pull emqx/emqx:4.2.5 可以上官网看最新版本&#xff0c;或直接…

vue动态修改浏览器title和icon图标

vue动态修改浏览器title和icon图标 实例代码 setTitleIcon(){var link document.querySelector("link[rel*icon]") || document.createElement(link);link.type image/x-icon;link.rel shortcut icon;link.href /002.png; // 图片放public目录document.getElem…

PHP8的类与对象的基本操作之类的实例化-PHP8知识详解

定义完类和方法后&#xff0c;并不是真正创建一个对象。类和对象可以描述为如下关系。类用来描述具有相同数据结构和特征的“一组对象”&#xff0c;“类”是“对象”的抽象&#xff0c;而“对象”是“类”的具体实例&#xff0c;即一个类中的对象具有相同的“型”&#xff0c;…

循环神经网络-02文本预处理

https://zh-v2.d2l.ai/chapter_recurrent-neural-networks/text-preprocessing.html 本节中&#xff0c;我们将解析文本的常见预处理步骤。 这些步骤通常包括&#xff1a; 将文本作为字符串加载到内存中。 将字符串拆分为词元&#xff08;如单词和字符&#xff09;。 建立一个…

QT---day3---9.19

1> 完成文本编辑器的保存工作 ui界面&#xff1a; 头文件&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QFontDialog> #include <QMessageBox> #include <QColor> #include <QColorDialog> #include <QFo…

计算机竞赛 深度学习 python opencv 实现人脸年龄性别识别

文章目录 0 前言1 项目课题介绍2 关键技术2.1 卷积神经网络2.2 卷积层2.3 池化层2.4 激活函数&#xff1a;2.5 全连接层 3 使用tensorflow中keras模块实现卷积神经网络4 Keras介绍4.1 Keras深度学习模型4.2 Keras中重要的预定义对象4.3 Keras的网络层构造 5 数据集处理训练5.1 …

IDEA全局替换快捷键有大坑---详解

1、ctl shift r 可选择范围最小就是包 那么必然就会造成全局替换过了&#xff01;&#xff01;&#xff01;&#xff01; 2、ctl r实现当前类全局替换 因为这个坑&#xff0c;浪费大爷我2小时。艹

认识一下Git

目录 Git Git下载 Git安装 Git初始化 Git操作 Git、GitLab、和Eclipse是公司中软件开发常用的组合&#xff1a; 1. Git&#xff1a;Git是一种分布式版本控制系统&#xff0c;用于跟踪文件和代码的变化。它提供了管理代码仓库的功能&#xff0c;可以记录每次提交的修改&am…

Python语言:列表初体验

列表是Python中的一个对象&#xff0c;他类似于C语言中的数组&#xff0c;可以存储许多数据&#xff0c;也可以称之为数据集合。他原则是可以存储不同类型的数据&#xff0c;一般不建议这样使用&#xff0c;有点奇怪&#xff1b;一般情况下一个列表中保存的都是同一种类型的数据…

Matlab中 * 与 .* 的区别

* 用于矩阵乘法 示例1&#xff1a; 注&#xff1a; 表示转置&#xff0c;即矩阵a的转置 乘以 矩阵b 根据矩阵乘法&#xff0c;r结果为&#xff1a; 示例2&#xff1a; 矩阵a 乘以 矩阵b的转置 根据矩阵乘法&#xff0c;结果为&#xff1a; .* 用于对应位置单个元素相乘 示例…

【虚幻引擎】UE5 VLC接入网络监控、视频直播、网络直播支持RTSP、RTMP

一、如何更新自己的插件匹配自己想要的UE版本 我们在网上下载的插件一般是UE4版本的插件&#xff0c;这个时候就需要我们自己去修改编译&#xff0c;接下来教大家修改插件来适配自己的引擎。 如果不想自己编译代码&#xff0c;可以直接找我拿编译好的UE5.0、UE5.1、UE5.2的插件…

[hive]搭建hive3.1.2hiveserver2高可用可hive metastore高可用

参考: Apache hive 3.1.2从单机到高可用部署 HiveServer2高可用 Metastore高可用 hive on spark hiveserver2 web UI 高可用集群启动脚本_薛定谔的猫不吃猫粮的博客-CSDN博客 没用里头的hive on spark,测试后发现版本冲突 一、Hive 集群规划(蓝色部分) ck1ck2ck3Secondary…

Meow

环境准备 操作系统:Kali Linux 或者 Windows工具:nmap,telnet nmap工具 [Kali 官网] 手册地址:https://www.kali.org/tools/nmap/ 摘要: Nmap is a utility for network exploration or security auditing. It supports ping scanning (determine which hosts are up), many…

Linux之动静态库

动静态库 动静态库的基本原理动静态库的认识动静态库特征静态库的打包与使用动态库的打包与使用 动静态库的基本原理 我们知道&#xff0c;生成一个可执行程序会经历以下四个步骤&#xff1a; 预处理&#xff1a;头文件展开&#xff0c;宏替换&#xff0c;去注释&#xff0c;…

iOS16新特性:实时活动-在锁屏界面实时更新APP消息 | 京东云技术团队

简介 之前在 《iOS16新特性:灵动岛适配开发与到家业务场景结合的探索实践》 里介绍了iOS16新的特性&#xff1a;实时更新&#xff08;Live Activity&#xff09;中灵动岛的适配流程&#xff0c;但其实除了灵动岛的展示样式&#xff0c;Live Activity还有一种非常实用的应用场景…

【Verilog教程】2.3 Verilog 数据类型

Verilog 最常用的 2 种数据类型就是线网&#xff08;wire&#xff09;与寄存器&#xff08;reg&#xff09;&#xff0c;其余类型可以理解为这两种数据类型的扩展或辅助。 线网&#xff08;wire&#xff09; wire 类型表示硬件单元之间的物理连线&#xff0c;由其连接的器件输…

脑网络图谱

前言 研究人脑面临的一个挑战是其多尺度组织和系统复杂性。我们对大脑组织的认识主要来源于离体组织学检查&#xff0c;如细胞结构映射。通过研究全脑微观结构特征的变化&#xff0c;可以划分为不同的脑区。然而&#xff0c;这种研究大脑组织的“局部”方法非常耗时、耗资源&a…

Python 图形化界面基础篇:创建工具栏

Python 图形化界面基础篇&#xff1a;创建工具栏 引言 Tkinter 库简介步骤1&#xff1a;导入 Tkinter 模块步骤2&#xff1a;创建 Tkinter 窗口步骤3&#xff1a;创建工具栏步骤4&#xff1a;向工具栏添加工具按钮步骤5&#xff1a;处理工具按钮的点击事件步骤6&#xff1a;启动…

window10下安装docker教程

要在Windows 10上安装Docker&#xff0c;您可以按照以下步骤进行操作&#xff1a; 在您的Web浏览器中&#xff0c;访问Docker官方网站&#xff1a;https://www.docker.com/get-started。然后&#xff0c;点击"Download Docker Desktop"按钮。 在下载页面上&#xff…

ruoyi-vue-pro 项目安装使用过程中的问题解决

ruoyi-vue-pro是功能比较多的一款前后端平台,因为刚接触ruoyi平台不久&#xff0c;为了更好了解ruoyi平台的相关功能&#xff0c;就本地部署了&#xff0c;作者主动屏蔽了部分功能&#xff0c;部分功能会提示功能能未启用&#xff0c;同时启用dev环境的时候是演示版本&#xff…