基于信号量的生产者消费者模型

文章目录

  • 信号量
    • 认识概念
    • 基于线程分析信号量
    • 信号量操作
  • 循环队列下的生产者消费者模型
    • 理论认识
    • 代码部分

信号量

认识概念

信号量本质:
计数器
它也叫做公共资源

为了线程之间,进程间通信------>多个执行流看到的同一份资源---->多个资源都会并发访问这个资源(此时易出现覆盖)---->数据不一致的问题----->保护起来---->互斥 和 同步

总结:解决问题的同时会伴随新问题的发生
互斥:任何时候只允许一个执行流(进程)访问公共资源,加锁完成
同步:多个执行流执行的时候,按照一定的顺序执行

被保护起来的资源,临界资源(如,管道)<------->非临界资源
访问该临界资源的代码叫做临界区<----->非临界区

维护临界资源就是维护临界区

原子性:只有两态,对于一件事要么没做要么就做完了(操作系统中)

如何理解信号量?
看电影为例,买票座位属于你,还是坐上去座位就属于你?
但有人占座,这个时候电影院内部的座位,就是多人共享的资源------公共资源
买票的本质: 是对资源的预订机制

有100个座位就绝对不会卖出101张票,如何做到这一点?
	维护一个计数器,
	int count = 100;//表示公共资源的个数

在这里插入图片描述
信号量:表示对资源数目的计数器,每一个执行流系想访问公共资源内的谋一份资源,不应该让执行流直接访问
而是先申请信号量资源.先对信号量计数器进行–操作,只要–成功了,就完成了对资源的预定机制
如果申请不成功,执行流被挂起阻塞

对于公共资源,在他的前面添加
在这里插入图片描述对于信号量为1的公共资源
int sem=1;
二元信号量—互斥锁—完成互斥功能
只能有一个人成功 ,其他执行流(进程)访问会出现阻塞

这样的表明允许访问公共资源的计数叫做信号量(信号灯)

分析细节问题:

1.每个进程都要看到同一个信号量资源-----就只能由OS提供,在IPC体系

2.信号量本质也是公共资源(还好信号量的访问并不复杂,只有-- ++ 的操作,如果访问出错,只要阻塞就可以)
这个操作也属于原子性
- - P
++ V
为什么不定义一个int来完成这个操作?
访问数据的不同进程间的操作,包含大量的拷贝等工作,所以单靠一个int不行

3.单个信号量(目前就这么理解)
struct sem
{
int count;//计数器
task_struct *wait_queue;//等待队列,对这个队列里面的进程进行操作(类似需要操作就对他进行)
}

基于线程分析信号量

现在基于线程概念再来整体理解一下:

1.信号量的本质是一把计数器
2.申请信号的本质就是预订资源
3.pv操作是原子的

怎么理解?

在上篇写的阻塞队列是一个公共资源,同时他的访问是一个整体形式去访问
现在假设这个公共资源是一个数组,那么不同线程可以访问不同数组的不同索引由此达到共同访问临界资源的目的.假设这个数组就是大小为7,有8个线程访问这个临界资源就会出现问题,所以这个时信号量就会起作用,他就相当于是一个计数器

所以上述情况,线程在访问之前都会先申请一个信号量,然后访问指定的一个位置(程序员进行维护),访问结束,释放信号量

这时,对于资源的访问判断已经由信号量充当了,所以不需要进行资源就绪的判断信号量申请成功,这个资源就一定能访问,这个也是原子性的
信号量为1,表示这个资源整体就是只能一个线程进行访问,这边就是互斥的

信号量操作

信号量的操作:
1.快速认识接口
信号量创建:

在这里插入图片描述

参数1:定义一个类似pthread_t类型的变量,这个类型在这边是sem_t类型,
参数2:在一个进程的线程之间共享(0表示这个种情况)还是在进程之间共享
参数3:这个信号量计数器的初始值
信号量销毁:

在这里插入图片描述
销毁信号量
信号量申请,也可以说是信号量等待(阻塞等待,有信号量才会进行后续操作,信号量的值减1)

在这里插入图片描述
这边只讨论普通阻塞方式
发布信号量:

在这里插入图片描述
表示信号量资源使用完毕,可以归还资源,将信号量的值+1

循环队列下的生产者消费者模型

理论认识

基于环形队列的生产者消费者问题–理论
环形队列:
逻辑上为环状,入队列出队列为同一个位置
判空判满可以加一个计数器或者是消耗一个空间的方式进行
这边不做讨论,因为信号量的操作就能完成判定
在这里插入图片描述
在循环队列中,

1.生产者不能把消费者套一个圈
2.消费者不能超过生产者

消费者生产者在这个结构中也是一样,为空或者为满会指向同一个位置,这个时候就不能并发访问,在其他情况下可以去并发访问,也就是并发进入临界区.

所以在为空 为满为互斥,生产者 消费者跑是同步,这是需要局部维持的"资源"的认识:
P:空间是资源(无空间了,不生产)
c:数据是资源(无数据了,不消费)
所以需要两个信号量来维护这个资源

伪代码:

p->sem_space:N
c->sem_data:0
生产者:
	p(sem_space)//预定资源,申请空间资源用来生产
	//生产行为,位置占据
	v(sem_data)//告诉消费者可以进行消费		
消费者:
	p(sem_data)//申请数据资源用来消费
	//消费行为
	v(sem_space)//告诉生产者当前位置为空可以来生产

代码部分

单任务的循环队列式生产者消费者模型
main.cc

#include "RingQueue.hpp"
#include <unistd.h>
void *Productor(void *args)
{
    RingQueue<int> *rq = static_cast<RingQueue<int> *>(args);
    int cnt = 100;
    while(true)
    {
        rq->Push(cnt);
        std::cout << "Productor done, the data is " << cnt << std::endl;
        cnt--;
    }
}
void *Consumer(void *args)
{
    RingQueue<int> *rq = static_cast<RingQueue<int> *>(args);
    while(true)
    {
        int data = 0;
        rq->Pop(&data);
        std::cout << "Consumer done, the data is " << data << std::endl;
        sleep(1);
    }
    
}
int main()
{
    pthread_t c, p;
    RingQueue<int> *rq = new RingQueue<int>();
    pthread_create(&p, nullptr, Productor, rq);
    pthread_create(&c, nullptr, Consumer, rq);   

    pthread_join(p, nullptr);
    pthread_join(c, nullptr);


    return 0;
}

RingQueue.hpp

#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>

const int defaultsize = 5;
template<class T>
class RingQueue
{
private:
    void P(sem_t &sem)//用于申请可以访问的资源
    {
        sem_wait(&sem);
    }
    void V(sem_t &sem)//资源使用完毕
    {
        sem_post(&sem);
    }
public:
    RingQueue(int size = defaultsize):_ringqueue(size), _size(size), _p_step(0), _c_step(0)
    {
        sem_init(&_space_sem, 0, size);
        sem_init(&_data_sem, 0, 0);
    }
    void Push(const T& in)//生产者放入数据
    {
        P(_space_sem);
        _ringqueue[_p_step] = in;
        _p_step++;
        _p_step %= _size;
        V(_data_sem);
    }
    void Pop(T *out)
    {
        P(_data_sem);
        *out = _ringqueue[_c_step];
        _c_step++;
        _c_step %= _size;
        V(_space_sem);
    }
    ~RingQueue()
    {
        sem_destroy(&_space_sem);
        sem_destroy(&_data_sem);
    }
private:
    std::vector<T> _ringqueue;
    int _size;

    sem_t _space_sem;
    sem_t _data_sem; 

    int _p_step;
    int _c_step;
};

引入任务后的生产者消费者模型
在原来基础上,将处理数据从int变为实际的Task,这边的Task只是一个算术运算,实际需求可根据实际情况去更改
在这里插入图片描述

即 将模板参数和生产者 消费者的实际内容进行修改
多生产 多消费内容的修改

与单生产,单消费的区别在于需要考虑生产者与生产者之间,消费者与消费者之间的关系
利用加锁的方式,让消费者之间可以进行不冲突的添加任务,消费者也是如此

所以在普遍情况下,各个生产者之间,消费者之间是互斥关系
先加锁还是先申请信号量?

答案是先分配信号量再申请锁,这样比较快,这就好比是先买票再排队,而不是排队到你之后再买票,后面的人还要等你买票,时间消耗大

main函数内部:
在这里插入图片描述productor和consumer

在这里插入图片描述
这样一个基于信号量的多线程生产者消费者任务就完成了.

关注我,虾片更精彩~~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python OpenCV 教学取得视频资讯

这篇教学会介绍使用OpenCV&#xff0c;取得影像的长宽尺寸、以及读取影像中某些像素的颜色数值。 因为程式中的OpenCV 会需要使用镜头或GPU&#xff0c;所以请使用本机环境( 参考&#xff1a;使用Python 虚拟环境) 或使用Anaconda Jupyter 进行实作( 参考&#xff1a;使用Anaco…

关于.NETCORE站点程序部署到nginx上无法访问静态文件和无法正确生成文件的问题解决过程。

我的netcore6项目&#xff0c;部署到IIS的时候&#xff0c;生成报告时&#xff0c;需要获取公司LOGO图片放到PDF报告文件中&#xff0c;这时候访问静态图片没有问题。 然后还有生成邀请二维码图片&#xff0c;这时候动态创建图片路径和图片也没有问题&#xff0c;可以在站点的…

14-58 剑和诗人32 - 使用矢量数据库增强 LLM 应用程序

GPT-4、Bloom、LaMDA 等大型语言模型 (LLM) 在生成类似人类的文本方面表现出了令人印象深刻的能力。然而,它们在事实准确性和推理能力等方面仍然面临限制。这是因为,虽然它们的基础是从大量文本数据中提取统计模式,但它们缺乏结构化的知识源来为其输出提供依据。 最近,我们…

Python:安装/Mac

之前一直陆陆续续有学python&#xff01;今天开始&#xff01;正式开肝&#xff01;&#xff01;&#xff01; 进入网站&#xff1a;可能会有点慢&#xff0c;多开几个网页 https://www.python.org 点击下载&#xff0c;然后进入新的页面&#xff0c;往下滑 来到File&#xff0…

成为编程大佬!!——数据结构与算法(1)——算法复杂度!!

前言&#xff1a;解决同一个程序问题可以通过多个算法解决&#xff0c;那么要怎样判断一个算法的优劣呢&#xff1f;&#x1f914; 算法复杂度 算法复杂度是对某个程序运行时的时空效率的粗略估算&#xff0c;常用来判断一个算法的好坏。 我们通过两个维度来看算法复杂度——…

c++ 多边形 xyz 数据 获取 中心点方法

有需求需要对。多边形 获取中心点方法&#xff0c;绝大多数都是 puthon和java版本。立体几何学中的知识。 封装函数 point ##########::getCenterOfGravity(std::vector<point> polygon) {if (polygon.size() < 2)return point();auto Area [](point p0, point p1, p…

leetcode--从中序与后序遍历序列构造二叉树

leeocode地址&#xff1a;从中序与后序遍历序列构造二叉树 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder …

Oracle基础以及一些‘方言’(二)

1、Oracle的查询语法结构 Oracle 的单表查询的语法结构&#xff1a; SELECT 1 FROM 2 WHERE 3 GROUP BY 4 HAVING 5 ORDER BY 6 其每个关键词的功能与MySQL中的功能已知&#xff0c;不过分页查询的关键词 limit 并不在Oracle的语法结构中。伪列&#xff1a; 在 Oracle 的表的使…

资料分析笔记整理

提升技巧多做题、少动笔、多分析 资料分析认识 国考一般20题(24~28分钟) 统计材料的类型包括单纯的文字、表格、图形以及由这些元素组成的复合类型材料 文字性材料:(30~60秒) 多段落型文字材料(时间、关键词、结构) 孤立段落文字材料(时间、关键词、标点[。;]) 表…

Linux 利用命名空间创建一个自己的“容器“

Linux 利用命名空间创建一个自己的"容器" 前置条件 创建一个目录存放容器mkdir /myapp准备静态编译busybox&#xff0c;操作系统自带的往往是依赖动态库的(本文使用的debian apt install busybox-static) 开始 使用unshare起一个独立命名空间.# 进入后/myapp目录…

如何理解http与https协议,他们有什么区别?

写在前面的话&#xff0c;关于 HTTP 和 HTTPS 的问题&#xff0c;常常会被很多学习者忽略&#xff0c;HTTP、HTTPS 不就是网址的开头吗&#xff0c;有啥好了解的&#xff0c;浏览器的引擎实现了这个协议&#xff0c;在开发关系不大&#xff0c;但想要深入一些理解数据传输原理&…

《植物大战僵尸杂交版》2.2版本:全新内容与下载指南

《植物大战僵尸杂交版》2.2版本已经火热更新&#xff0c;带来了一系列令人兴奋的新玩法和调整&#xff0c;为这款经典的塔防游戏注入了新的活力。如果你是《植物大战僵尸》系列的忠实粉丝&#xff0c;那么这个版本绝对值得你一探究竟。 2.2版本更新亮点 新增看星星玩法 这个新…

HarmonyOS鸿蒙DevEco Studio无法连接本地模拟器

使用DevEcoStudio 5.0.3.403版本 发现无法选择模拟器 解决方法&#xff1a; 1、打开模拟器 2、关闭DevEco Studio&#xff0c;&#xff08;不要关闭模拟器&#xff09; 3、重新打开DevEco Studio。

效果惊人!LivePortrait开源数字人技术,让静态照片生动起来

不得了了,快手已经不是众人所知的那个短视频娱乐平台了。 可灵AI视频的风口尚未过去,又推出了LivePortrait--开源的数字人项目。LivePortrait让你的照片动起来,合成逼真的动态人像视频,阿里通义EMO不再是唯一选择。 让图像动起来 LivePortrait 主要提供了对眼睛和嘴唇动作的…

Junior.Crypt.2024 CTF Web方向 题解WirteUp 全

Buy a cat 题目描述&#xff1a;Buy a cat 开题 第一思路是抓包改包 Very Secure App 题目描述&#xff1a;All secrets become clear 开题 乱输一个密码就登陆成功了&#xff08;不是弱口令&#xff09; 但是回显Your role is: user 但是有jwt&#xff01;&#xff01;&a…

线程池【开发实践】

文章目录 一、为什么要用线程池1.1 单线程的问题1.2 手动创建多线程的问题1.3 线程池的作用&#xff08;优点&#xff09;1.4 线程池的使用场景 二、线程池的基础知识2.1 线程池的核心组件2.2 JUC中的线程池架构2.3 线程池的配置参数2.4 线程池常见的拒绝策略&#xff08;可自定…

看影视学英语(假如第一季第一集)

in the hour也代表一小时吗&#xff1f;等同于in an hour&#xff1f;

科研绘图系列:R语言小提琴图(Violin Plot)

介绍 小提琴图(Violin Plot)是一种结合了箱线图和密度图的图表,它能够展示数据的分布密度和分布形状。以下是对小提琴图的详细解释: 小提琴图能表达: 数据分布:小提琴图通过在箱线图的两侧绘制曲线来展示数据的分布密度,曲线的宽度表示数据点的密度。集中趋势:箱线图部…

渲染农场怎么用更省钱?渲染100邀请码1a12

现在越来越多的设计师开始使用渲染农场&#xff0c;其中收费是个大问题&#xff0c;怎么用渲染农场才能更省钱呢&#xff1f;今天我们就来看下吧。 1、明确渲染方式 要根据不同情况选择合理的渲染方式&#xff0c;比如渲染农场就适合大场景渲染和紧急出图情况&#xff0c;其他…

DDR3 SO-DIMM 内存条硬件总结(一)

最近在使用fpga读写DDR3&#xff0c;板子上的DDR3有两种形式与fpga相连&#xff0c;一种是直接用ddr3内存颗粒&#xff0c;另一种是通过内存条的形式与fpga相连。这里我们正好记录下和ddr3相关的知识&#xff0c;先从DDR3 SO-DIMM 内存条开始。 1.先看内存条的版本 从JEDEC下载…