学习系统编程No.35【基于信号量的CP问题】

news2024/12/25 9:05:59

引言:

北京时间:2023/8/2/12:52,时间飞逝,恍惚间已经来到了八月,给我的第一感觉就是快开学了,别的感觉其实没有,哈哈!看着身边的好友网络相关知识都要全部学完了,就好像它们工业革命都要完成了,而我还在刀耕火种,哈哈哈!他们在高速发展阶段,我还在休养生息,哈哈哈!不怕,正所谓没有压力没有动力,让压力来的再猛烈一些吧!咱无所畏惧,八月就是咱逆分翻盘之月,舍我其谁,冲冲冲!这句话我好想在哪见过,哈哈哈!别笑,我真的在很严肃的看待这件事。八月没有什么拓展内容,本来还想着在暑假的时候提高一下自己的做题能力,可惜,现在连课都学不明白,可能是当时无知以为自己时间很多,也可能确实是我们自己没把握好,反正现在不管那么多,八月我们的目标就是将网络搞定。废话不多说,进军网络之前,我们还是先把有关系统方面的知识先给搞定,今天就让我来看看基于信号量知识的生产消费模型吧!

在这里插入图片描述

基于环形队列的CP问题

上篇博客由于时间原因,这部分有关信号量接口实操的知识我们没有讲解,来到该篇博客,我们在重温生产消费模型的基础上,来看看如何实现信号量对共享资源中资源数量控制的同时,让多线程可以安全的访问共享资源吧!

1.复习环形队列

为什么使用环形队列?
在学习信号量时,我们重点强调了为什么要学习信号量,并且明白信号量分为二元信号量(互斥锁)和多元信号量,信号量就是一个对共享资源中资源数量的预定机制,结合当时我们没有使用信号量实现的生产消费模型我们可以发现,使用和不使用信号量的区别在于共享资源中是否存在多个临界资源需要被控制。在之前学习有关BlockQueue队列的CP模型我们可以发现,它并不存在多个临界资源,所以我们是直接采用互斥锁和条件变量的形式对其进行同步机制控制,也就是对那唯一的共享资源进行保护就行。而当我们今天想要实现一份有信号量知识的CP模型,那么前提就是需要有多个临界资源,而我们的环形队列就能很好的实现这一效果。

回顾环形队列相关的知识
明白了为什么要回顾环形队列之后,此时我们正式来复习一下环形队列,毕竟这块知识已经学习快一年了(去年11月份学的),并且当时出处茅庐,虽然也写了博客,但是当时的博客并没有非常用心,所以这一块知识给我的感觉比较模糊,该篇博客我们就来重点复习一下,由于这部分知识属于初阶数据结构,并不适合展开理解,也就是相关代码实现我们不体现出来,感兴趣的小伙伴可以参考我之前的代码实现,所以这里我们重点复习一下有关环形队列的概念知识,也就是环形队列的实现原理和特征。 我们都知道无论学习什么都是由浅入深,由概念到实操,如果一上来就是实操,那么你只会感觉天昏地暗,什么都听不懂,好比之前我们在学习生产消费模型,每个人的实操代码都有可能是不同的,但是其中的原理生产者和消费者的三种关系是谁都不能改变的,所有人都必须紧紧围绕这个原理来实现自己的CP模型。所以同理在数据结构中,无论是那种数据结构,它们本质的不同就在于设计原理不同,所以你想要看懂一份某数据结构的代码,前提就是你对该数据结构的设计原理了如指掌,同理你想实现一份代码,也是这个道理。现在就让我们来看看环形队列是由那些原理组成的吧!

环形队列原理和概念
环形队列也叫循环队列,本质是通过一个数组或者链表实现,同理只要按照环形队列的特征来实现,无论使用数组还是链表都没有太大区别,最本质的区别还要归咎于数组和链表的区别,也就是数组和链表各自的优缺点(这里我不展开复习),所以我们只要明白环形队列就是一个固定大小但可以重复使用的队列,其最大的特征在于开辟空间存储数据时,要多开辟一个空间(无论是数组还是链表实现),该空间用于解决环形队列最大的问题:判空判满问题,也就意味着我们在实现环形队列时,用户如果想要一个可以存储 K(10)个数据的环形队列,那么在环形队列内部new空间时就需要new K+1个空间,当然这一过程由于被封装的原因,上层用户并不能体会到,但是你下层代码为了实现这一功能,你就必须这么做(同理很多不看源码你无法理解的功能都是通过这种理念实现)。所以我们根据这一特征,此时就能明白如果环形队列是通过数组实现,那么此时它就需要通过两个整形数据front和tail作为数组下标来控制队列的循环过程,当(tail+1) % (K+1) = front时,就表示此时环形队列满了,而如果我们的环形队列是通过链表来实现,那么此时它就需要通过两个结点指针来控制队列的循环过程,当tail->next = front时表示环形队列满了。明白了这些知识之后,对于环形队列的判空判满简直不要太简单,明白了环形队列的判空判满对于环形队列剩余的知识当然也不要太简单,总而言之: 环形队列没什么重点,重点就在于理解环形队列为什么叫做环形队列,也就是如何实现对空间的循环使用。 取模运算(a % b)可用于获取到一个0~b-1之间的数,常用于对数组越界和数组下标的控制。

在这里插入图片描述

2.正式进入CP问题

明白了上述有关环形队列知识的学习,此时顺理成章正式进入有关信号量实操问题,也就是我们一直说的使用信号量来控制生产消费模型的实现,所以接下来我们就来看看,如何让信号量控制环形队列中的临界资源吧!

同理,实操的前提是对相关知识概念非常清晰,首先我们就来谈谈在环形队列中信号量是如何控制资源以及使用信号量实现生产消费模型的特征,也就是基于信号量的生产消费模型的实现原理。此时我们明白,对于生产者和消费者来说它们关注的资源是不一样的,生产者关注的是环形队列,也就是共享资源中的空间资源,而消费者关心的则是共享资源中的数据资源,也就是当我们把一整块共享资源划分为一份一份的临界资源时,此时生产者和消费者之间关心的资源不同,生产者关心的是该共享资源中可写入数据的空间数量,而消费者关心的是生产者写入数据之后产生的数据数量。所以当我们有了这两个抓手之后,信号量实现生产消费模型的问题我们就差不多搞定了,因为我们已经将该生产消费模型中的信号量给找到了,也就是将共享资源中的空间资源看做是生产者的信号量,而共享资源中的数据资源看做是消费者的信号量,结合之前学习的有关信号量的知识,此时我们就知道,只有当共享资源中还有未存储数据的空间,此时才允许某个生产者线程去申请空间信号量(调度器决定),当获取到了空间信号量之后才能继续向后执行,反之等待。只有当共享资源在生产者生产之后,也就是共享资源中有数据资源时,才允许某个消费者线程去申请对应的数据资源,同理获取之后才允许向后执行。当然具体信号量是如何实现没有对应信号量资源时,让线程发生等待,这个由底层代码决定,这里我们不关心,同理我们只关心信号量的使用规则和相应的功能。

如何实现信号量的P/V操作
明白了上述对信号量实现生产消费模型的简易分析,此时我们就知道,在该生产消费模型中存在两个信号量,一个是生产者的空间信号量,一个是消费者的数据信号量,那么此时问题又来了,我们应该如何对这两个信号量进行控制呢?当然对于信号量的控制本质就是使用我们上篇博客中谈到的sem_post接口和sem_wait接口,也就是伴随信号量产生的P/V操作。首先,肯定是要有两个不同的信号量来分别表示空间信号量和数据信号量,当我们在实现代码时我们就可以定义为_space_sem和_data_sem,然后通过信号量初始化接口sem_init进行初始化,并且因为空间资源先天存在,数据资源后天由生产者生产,所以我们将_space_sem初始化为num(环形队列大小决定),_data_sem初始化为0。然后,当多个生产者线程和消费者线程开始同时访问共享资源时,因为空间信号量存在,数据信号量不存在,所以此时生产者线程可以分配到信号量(调度器决定)且对应空间信号量发生P(_space_sem)操作,直到_space_sem数量为0,生产者线程全部等待,而消费者线程由于数据信号量天生不存在,所以在生产者进行V(_data_sem)操作之前,全部等待,只有当_data_sem数量不为0,此时消费者线程才可能分配到信号量且对应数据信号量发生P(_data_sem)操作,完成消费之后同理进行V(_space_sem)操作,将空间资源释放。从而如此以往,循环往复的实现生产和消费。

注意: 生产消费模型并不代表只有当生产者线程生产完成之后,消费者线程才能消费,从之前学习有关BlockQueue模型的生产消费模型我们也能看出,无论是生产者还是消费者只要其抢到了锁并且符合条件变量,那么它就可以执行,只不过对于BlockQueue来说,我们是使用同一把锁的形式来控制生产者和消费者之间的同步关系,从而实现共享资源只能被生产者或者消费者其中一个线程执行,而此时对于CircleQueue模型来说,我们支持生产者和消费者同时访问共享资源,但不支持它们同时访问该共享资源中的同一份临界资源,从而实现同步关系。那么此时这个同步关系主要体现在哪里呢?信号量会给你答案,我们通过控制两个不同信号量之间的P/V操作来实现这一同步机制,从空间信号量产生数据信号量这一个原理我们可以很好理解,也就是只有当进行了生产者生产,数据信号量才会增加,消费者才能消费这一原理,我们能很好的体会到生产者和消费者之间的同步关系。

3.完整代码实现

3.1 单生产单消费

在这里插入图片描述

但注意: 上述代码只有在单生产单消费的场景下才能运行,也就是如果想要在多生产多消费的场景下运行,此时我们就要让多线程之间发生互斥,当然也就是通过互斥锁来实现,那么为什么呢?首先明白,虽然像上述这种类对象,本质所有线程在访问该类中的接口时,都会将该类的对象,也就是上述对象给拷贝一份到自己的栈空间,从而让该类中的接口看做是一个可重入函数接口,但是由于此时我们对类对象c_step和p_step(看成局部变量)存在修改数据的行为,所以此时线程之间就会因为竞态条件的发生,造成数据的不确定性,引发线程安全问题,因此我们就需要使用互斥的方式,来保护该类对象的安全。明白了这个原因之后,此时下述进行加锁之后的代码,就是我们要的多生产多消费代码,如下代码所示:

3.2 多生产多消费

在这里插入图片描述
最后明白,无论是单生产单消费,还是多生产多消费,本质并没有说谁的效率更高,并不是单纯的认为多生产多消费的效率就更高,如:想要实现多生产多消费就需要进行加锁操作,对于加锁肯定是会浪费效率的,并且由于多生产多消费,那么多线程之间的上下文切换也会造成一定的效率损失,所以具体使用多生产多消费,还是单生产单消费,是需要通过问题场景来决定的,同理,使用信号量和不使用信号量,也需要具体问题具体分析。总而言之:还是那句话,CP问题最大的好处不在于生产者和消费者之间的串行执行过程,而是在于线程间的解耦和并发问题,也就是之前说过的,线程在等待期间(无论是信号量、互斥锁)它可以访问其它资源(无论是否为共享资源),从而让系统内部的资源利用率提高,从而增强系统的响应速度。

总结:该篇博客有关信号量实操相关的知识,也就是基于信号量的CP问题我们就搞定啦!并且有关多线程相关的知识我们就要学完了,下篇博客应该就是我们对多线程知识的最后一篇博客,当然也就是有关系统编程相关知识的最后一篇博客,网络我来啦!See you!

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

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

相关文章

Linux系统---进程概念

文章目录 冯诺依曼体系结构操作系统(OS)进程的理解 进程状态 进程优先级 环境变量 进程地址空间 一、冯诺依曼体系结构 我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系。 如图为冯诺依曼体系结构图&…

【BEV感知】2-BEV感知算法数据形式

文章目录 1 图像1.1 如何获取图像特征? 2 点云2.1 稀疏性2.2 无序性2.3 为什么要用点云?2.4 如何提取点云特征?Point-basedVoxel-based 3 图像点云 1 图像 图像是由相机生成的,是将三维世界中的坐标点(单位为米&#…

I- yh的线段(2023河南萌新联赛第(四)场:河南大学)

链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 yh喜欢好线段,好线段即两条线段相交且不与其他线段重合的线段。 两条线段[l1,r1]和[l2,r2]相交(如果存在至少一个x,使得l1≤x≤r1和l2≤x≤r2,则认为两个线段…

Linux运维面试题(四)之Linux服务管理

Linux运维面试题(四)之Linux服务管理 4.1 SSHSSH的登录验证方式SSH的登陆端口(默认22)和监听设置(/etc/ssh/sshd_config)SSH的登录用户限制(/etc/ssh/sshd_config PermitRootLogin)SSH的登录超时设置(/etc/…

软件测试之Docker常见问题汇总!附解决方法!

1、配置国内源进行docker安装,报错 HTTP Error 404 - Not Found 【整整200集】超超超详细的Python接口自动化测试进阶教程,真实模拟企业项目实战!! 原因: 由于配置国内镜像源时,把地址写错了,导…

使用火山云搜索ESCloud服务构建图文检索应用(以文搜图/以图搜图)

图文检索在生活中具有广泛的应用,常见的图片检索包括基于文本内容搜索和基于图片内容搜索。用户通过输入文字描述或上传图片就可以在海量的图片库中快速找到同款或者相似图片,这种搜索方式被广泛应用于电商、广告、设计以及搜索引擎等热门领域。 本文基…

Windows服务器中IIS部署图片文件夹—超详细图文

Windows服务器中IIS部署图片文件夹—超详细图文 注意:部署前请先安装IIS IIS安装步骤可参照:win11安装IIS步骤—图解_win11 iis_咏絮v的博客-CSDN博客 1、打开 IIS管理器—选择【网站】后右键【添加站点】 2、【添加网站】(填写网站名称/物理路径/IP地…

2023华数杯数学建模C题思路代码 母亲身心健康影响

C 题 母亲身心健康对婴儿成长的影响 母亲是婴儿生命中最重要的人之一,她不仅为婴儿提供营养物质和身体保护, 还为婴儿提供情感支持和安全感。母亲心理健康状态的不良状况,如抑郁、焦虑、 压力等,可能会对婴儿的认知、情感、社会行…

【java】【maven】【基础】MAVEN安装配置介绍

目录 1 下载 2 安装-windows为例 3 配置环境变量 3.1 JAVA_HOME 3.2 MAVEN_HOME 3.3 PATH 3.4 验证 4 MAVEN基础概念 4.1 仓库概念 4.2 坐标概念 4.2.1 打开网址 4.2.2 输入搜索内容junit 4.2.3 找到对应API名称点击 4.2.4 点击对应版本 4.2.5 复制MAVEN坐标 4.3 配置…

计算机网络(4) --- 协议定制

计算机网络(3) --- 网络套接字TCP_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/132035757?spm1001.2014.3001.5501 目录 1. 协议的基础知识 TCP协议通讯流程 ​编辑 2.协议 1.介绍 2.手写协议 1.内容 2.接口 …

Vulnhub: blogger:1靶机

kali:192.168.111.111 靶机:192.168.111.176 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.176 在80端口的/assets/fonts/目录下发现blog目录,访问后发现为wordpress 利用wpscan发现wordpress插件wpdisc…

WiFi爆破实战

提示:本文记录了博主的一次WiFi爆破实战 文章目录 写在前面一、将网卡连接Kali虚拟机二、网卡配置骤2.1 识别网卡2.2 净化环境2.3 启动监听2.4 探测周边WiFi 三、实施攻击3.1 对选定的目标WiFi实施监听3.2 发起DOS攻击3.3 实施爆破 写在最后 写在前面 提示&#xf…

LNMP搭建及论坛搭建

一、LNMP LNMP架构是目前成熟的企业网站应用模式之一,指的是协同工作的一整套系统和相关软件, 能够提供动态Web站点服务及其应用开发环境。LNMP是一个缩写词,具体包括Linux操作系统、nginx网站服务器、MySQL数据库服务器、PHP(或…

实用,3分钟免费生成中小学新生录取查询系统

在新学期开始之际,作为招生负责人,您是否已经做好准备来迎接新学年的招生工作呢?录取新生所需的任务包括成绩信息的录入、招生要求的核对以及新生录取信息的查询公布,这些繁重的工作给负责招生的老师带来了巨大的压力和挑战。 为…

Dockerfile构建LNMP镜像

建立工作目录 [rootlocalhost ~]# mkdir lnmp [rootlocalhost ~]# cd lnmp/ 编写Dockerfile文件 [rootlocalhost lnmp]# vim Dockerfile [rootlocalhost lnmp]# ll 总用量 4 -rw-r--r--. 1 root root 774 8月 3 14:54 Dockerfile [rootlocalhost lnmp]# vim Dockerfile #基础…

2023年华数杯A题

A 题 隔热材料的结构优化控制研究 新型隔热材料 A 具有优良的隔热特性,在航天、军工、石化、建筑、交通等 高科技领域中有着广泛的应用。 目前,由单根隔热材料 A 纤维编织成的织物,其热导率可以直接测出;但是 单根隔热材料 A 纤维…

软件为什么要进行性能压力测试?

软件为什么要进行性能压力测试?随着软件应用的不断增多和复杂度的提高,软件的性能对用户体验和业务成功至关重要。性能问题可能导致软件运行缓慢、崩溃或无响应,给用户带来不便甚至损失。为了确保软件能够在高负载和压力下正常运行&#xff0…

spring-bean的生命周期和怎么配置spring-bean的后置处理器

😀前言 本章是spring基于XML 配置bean系类中第6篇讲解spring-bean的生命周期和怎么配置spring-bean的后置处理器 🏠个人主页:尘觉主页 🧑个人简介:大家好,我是尘觉,希望我的文章可以帮助到大家…

Storm学习之使用官方Docker镜像快速搭建Storm运行环境

文章目录 0.前言搭建完的效果 1.教程1.1.docker 安装 zookeeper1.2. 安装 storm nimbus1.3.docker 安装 supervisor1.4.docker 安装 storm-ui1.5.查看已经启动的容器1.6.提交topology到 storm集群 2.总结3.参考文档 0.前言 Apache Storm 官方也出了Docker 镜像 https://hub.do…

Python3 高级教程 | Python3 CGI编程(二)

目录 一、什么是CGI 二、网页浏览 三、CGI架构图 四、Web服务器支持及配置 五、第一个CGI程序 六、HTTP头部 七、CGI环境变量 八、GET和POST方法 (一)使用GET方法传输数据 (二)简单的url实例:GET方法 &#x…