你了解system V的ipc底层如何设计的吗?消息队列互相通信的原理是什么呢?是否经常将信号量和信号混淆呢?——问题详解

        前言:本节主要讲解消息队列, 信号量的相关知识。 ——博主主要是以能够理解为目的进行讲解, 所以对于接口的使用或者底层原理很少涉及。 主要的讲解思路就是先讨论消息队列的原理, 提一下接口。 然后讲解ipc的设计——这个设计一些底层原理。 最后就是会让友友们理解一下信号量的相关概念。 

        ps:本届内容设计共享内存, 友友们务必学完共享内存后再来观看哦

目录

消息队列的原理

消息队列的接口

msgget

msgctl

ipc在内核里面的设计

信号量

储备知识

理解信号量

信号量接口

 信号量与进程间通信


消息队列的原理

        本节讲述的消息队列是system V标准的。 我们知道的是, 我们的进程, 因为是用户写的代码, 有操作系统的task_struct以及地址空间, 所以它是在用户和操作系统之间的。 而消息队列,是属于内核的。那么这里就是下图的样子:

        想要让上面两个进程a 和 b进行通信, 前提是,必须先让两个进程看到同一份资源!!!(这一句话是通信领域的结论, 地位就相当于管理层面的先描述再组织)

        现在我们要知道的是这个同一份资源, 有可能是文件缓冲区, 有可能是内存块。 所以, 公共资源种类的不同, 决定了通信方式的不同。 其中,以文件的形式给我们一个文件缓冲区, 这就叫做管道。是否允许匿名,这个就叫做匿名管道给我们一个内存块, 映射到地址空间, 这个就叫做共享内存;也可以给我一个队列, 这个队列就是我们在数据结构里面学到的那个队列, 也就是消息队列。 现在来谈这个队列。

        这个队列, 如果我们想要让两个进程a,b能够进行通信。 就必须让两个进程看到同一个队列。  当两个不同进程看到同一个队列之后,我们知道, 两个进程想要通信, 就要能够将数据块入队列当中。 但是问题来了, 两个进程怎么保证, 能够拿到对方的数据块呢?这个是因为允许不同的进程能够向内核中发送不同类型的数据块。 这些数据块假如a进程的是a类型的数据块, b进程的假如是b类型的数据块。 那么a进程要获取b进程的通信, 就可以拿到消息队列里面的b类型的数据块。 所以, 综上, 消息队列是什么?——消息队列的原理就是:a进程, b进程以数据块的形式发送数据进行通信!!!

消息队列的接口

        注:消息队列的接口不作为博主讲解的重点, 如果想要学习相关接口的友友自行去查阅相关资料哦。

msgget

        里面的返回值是int类型。 成功返回,会返回一个消息队列标识符。 失败返回-1。——无需指明大小, 只需直接创建即可。  第二个参数是就是那个key(使用路径和项目id确定的唯一key), 第三个参数就是创建消息队列的使用方式。

msgctl

这个函数是用来控制消息队列,这里不讲解这个接口的用法, 我们用这个接口和信号量的控制接口, 以及共享内存的控制接口来进行对比, 下面是信号量和共享内存的控制接口:

        由上面三个函数我们就可以观察到, 我们的进程间通信, 是被精心设计过的, 无论是我们的共享内存, 还是我们的消息队列, 亦或者我们的信号量。 他在内核层面上都有我们的semid_ds这样的结构, XXXid_ds结构体。 并且, 他们三个的XXXid_ds结构体里面第一个成员一定是struct_ipc_perm XXX_perm。并且, 这种结构体里面包含的字段全部都是一样的, 都是key还有各种权限。 

ipc在内核里面的设计

        在操作系统中, 所有的IPC资源, 都是整合进操作系统的IPC模块中的在以后的过程中, 我们管理共享内存, 管理消息队列, 管理信号量, 其实本质上就是管理下面这三种结构体:

        那么我们如何把这些数据结构管理起来呢?在操作系统当中, 其实也是用数组管理的:

        如果我们今天创建一个共享内存, 那么操作系统当中, 就要为我们创建shmid_fd这样的结构。 那么我们就要把shmid_ds的第一个字段填到数组的零号下标里面。 

        那么, 如果后来我们又创建了一个消息队列. 没关系, 虽然我们的struct_ds的类型不一样, 但是我们的结构体的第一个字段和上面的字段是一样的。 所以, 我们就把这个第一个字段的地址, 填到数组的二号下标里面。 同样的信号量. 所以, 从此往后, 我们要管理操作系统内部的不同的IPC资源要如何如何进行管理呢?——答案是先描述:对于不同的资源, 我们可以使用不同的描述的方式。 再组织, 我们可以对不同的资源进行增删查改, 最后转化为对该数组进行增删查改。

        未来呢, 我们一个进程如果想要申请一个共享内存, 那么申请共享内存, 就会给我们一个key, 然后操作系统就会遍历这个数组, 找到每一个ipc资源, 比较key, 确认是否已经创建过共享内存。 ——其中的, 这里的每一个ipc_perm结构, 他对应的数组的下标, 就是我们所说的shmid或者XXXid!!!

        那么, 我们如何利用这个数组元素访问XXXid_ds里面的其他字段呢?——只需要强转一下我们的类型——((shmid_ds*)array[])->某个字段——但是问题来了, 它是怎么知道要强转成为哪一个类型呢?ipc_perm是操作系统在用户层做的让我们用户看到的属性, 但是内核层面上叫做kern_ipc_perm, 这个东西里面有mod, delete等等。 其中mod里面就有一个选项, 这个选项是一种类型标志位, 让代码去区分自己是哪一种ipc资源。——也就是说, 操作系统能够区分指针指向的对象的类型(事实上, 我们也可以, 就是在对象里面添加一个标志位即可)。

        其中, 这个数组其实就是实现了多态!!!而其中的ipc_perm就是基类, 其他的字段就是子类。 指针数组指向了这些ipc_perm, 就是实现了多态。 

        这个数组是操作系统层面创建的数组, 和进程没有关系, 所以这个下标和文件描述符并不类似。 shmid这个下标是线性递增的。 就比如我们今天申请了这个资源, 释放掉, 下次再申请, 这个资源的数字会变大。 ——不会因为释放而减小。 但是不需要担心越界, 因为他是会发生回绕的, 但是我们的这个数组的下标永远是从零开始的, 只是在使用的时候会有一个起始计数器, 我们最后的shmid就会使用这个起始计数器加上我们的小标进行计算。 

信号量

储备知识

理解信号量, 我们需要先有一些储备知识, 先回忆一下这一张图

        这张图, 当a进程想要读取, b进程想要写入。 他们会不会发生错乱呢? ——比如我们今天a进程想要给b进程发送100字节, 并且这100个字节是应该整体被读取的。 但是如果这个时候a刚写了50个字节, b进程就过来读了, 那么b进程就可能把这50个字节先读走。 ——这就造成了一种情况, b进程只读取了a进程想要发给他的信息的一部分, 这就是数据不一致问题

  •         那么a和b看到的同一份资源, 我们叫做共享资源, 因为是共享的, 如果不加保护, 可能会导致数据不一致问题。
  •         那么我们要如何保护呢?就要用到一种加锁的方式。通过加锁保证一种工作状态。——这就是互斥访问。即:任何时刻只允许一个执行流, 访问共享资源。 ——这种概念称之为互斥, 就比如我们去ATM机取钱, 我们一个人去取钱了, 其他人就不能够进去了。
  •         共享资源是任何时刻只允许一个执行流访问(访问就是指的执行访问代码)的资源, 我们就叫做临界资源 管道就是临界资源, 但是临界资源一般是内存空间 
  •         假设我们写了100行代码, 其中的5 ~ 10行在访问临界资源。 所以, 这些访问临界资源的代码, 就叫做临界区!!!

        通过上面的讲解, 我们就能解释一个现象: 假如有五个进程在死循环的打印hello world。 为什么显示器上面的消息是:错乱的, 混乱的并且和命令行混在一起的。——这是因为我们在向显示器打印数据的时候, 是先向显示器文件的缓冲区中打印数据, 然后再将显示器文件的缓冲区的内容刷到显示器上面打印出来。 这其中, 我们的进程, 所有的进程都在向我们的显示器文件的缓冲区中打印数据, 很显然他们都能够看到我们的显示器文件, 那么我们的显示器文件就是一种共享资源又因为我们的显示器文件没有保护机制, 那么多进程一起打印的时候, 就会发生数据不一致问题 想要进行保护, 就要通过加锁互斥访问的形式变成临界资源!!!

理解信号量

        那么如何理解信号量?信号量的本质, 其实就是一把计数器!类似于一个整数的的计数器:比如 int cnt——信号量是用来秒数临界资源中,资源数量的多少!!!

       临界资源中的资源数量是什么意思?——就比如我们去看电影, 电影院有100个座位, 那么对应着就一定有100张电影票。当我们去看电影的时候, 如果我们买了票了, 但是没有去。那么此时电影院其实就是这么一个大的临界资源, 我们每一人对应每一个进程, 每一张票就代表着我们能够访问电影院里面的一个座位。 那么请问我们去看电影, 是我们做到这个座位上票是我的? 还是我们将票买到了, 这个座位是我的?是不是我们将票买到了, 这个座位就是我的了呢?——所以, 买票的本质, 是对资源的预定机制!!!对于电影院, 需要维护一个票数的计数器, 每卖出一张票, 我们的计数器就要减一, 放映厅里面的资源就会少一个!!!票数计数器到零之后, 资源已经被申请完毕了!!! ——就如同下图:

        这一块临界资源按照某个单位划分为一块一块的。 假如今天有一个执行流访问临界资源, 那么这个执行流可能只访问临界资源的一部分。 

        对于我们的临界资源, 如果今天有一个执行流想要访问临界资源, 那么他可能只访问其中的一部分。 我们对应的系统在临界资源的使用上, 我们可以让整个临界资源只被这一个执行流访问。但是这个执行流只访问临界资源其中的一块, 所以系统就可以只把这一块分配给这个执行流。 当又来了一个执行流的时候, 这个执行流也只是访问一块资源, 那么这个时候就没必要将整块资源全部锁住, 只需要将刚刚第一个执行流的资源锁住, 将那一块资源给第二个执行流就行了。 所以我们把临界资源拆成一小份, 前提是能够被拆成一小份, 并且每个执行流只使用一小份资源, 这种情况下, 我们就可以使得这两个执行流同时都进来访问。 这种情况可以提高多执行流访问临界资源的并发度, 一定程度上提高效率。 

        在这种情况下, 我们最怕的是, 多个执行流访问同一个资源, n个资源但是有n+个执行流。 排除我们分配资源的bug问题, 为了防止出现n个资源有n+个执行流的问题, 我们就会引入一个计数器:

int cnt = 15;(假如有15个资源)

int number = cnt--; (每申请一个资源就渐渐)

cnt <= 0; (小于等于0的时候资源没了, 不再分配资源, 直到有资源空出来了!)

那么, 经过上面的解释, 我们可以得出结论——

  • 1、我只要申请计数器成功了, 就表示我具有访问资源的权限了!
  • 2、申请了计数器资源, 就代表我当前要访问我的资源了吗?——并没有, 但是我们只要申请成功了, 并且没有释放, 那么这里面的资源就一定要有一个供我使用。——所以申请计数器资源的本质就是对资源的一种, 预定机制。
  • 3、如果多个执行流全部都申请, 那么计数器减为零, 就不能申请了。——这个就说明计数器可以有效保证进入共享资源的执行流的数量。
  • 4、所以每一个执行流想访问共享资源的时候, 不是直接访问, 而是先申请计数器资源, 就如同我们看电影需要先买票。

        那么, 上面提这么多还是没有提到信号量, 但是其实我们一直都在说信号量——因为这个“计数器”就被成为信号量!!!

        现在再来看这个问题, 如果电影放映厅里面只有一个座位呢?——是不是也就意味着, 我们只需要一个值为一的计数器。——那么如果有人想买票, 就需要先抢这个座位, 并且所有人中, 只有一个人能够抢到, 也就只有一个人能看电影。 在放电影期间, 只有一个执行流在访问临界资源。 ——这个概念叫做互斥。 我们把只能为一为零两态的计数器叫做二元信号量, 本质就是一个锁!!!

        那么, 我们要访问临界资源, 先要申请计数器资源, 所以信号量计数器资源的本质, 不也就是共享资源吗?——所以, 刚刚我们举得例子当中的int本身就是一个临界资源, 而这个临界资源是用来保护我们的要访问的临界资源的, 但是我们的信号量在保证别人的前提下, 是不是也要保护自己是安全的?(因为数据不一致可能发生在计数器上面)——那么请问这个计数器临界资源减减的时候是不是安全的呢?——答案是不是的:cnt--在c语言上, 是一条语句, 但是变成汇编语言, 那么至少会变成多条汇编语句,我们知道cnt是保存在内存中的, 而cnt在--的时候要转移到cdu中进行计算, 那么减减操作就是:

        1、首先cnt变量的内存从内存转移到cpu中的寄存器中。 2、在cpu内进行计算。 3、将计算结果写回cnt变量的内存位置。

        但是这里有一个问题:就是进程在运行的时候, 可以随意的切换, 有可能在我们的三步执行过程之间的某一个邻接点的时候,这个进程就被切走了!!切走的时候, 多执行流都访问这个变量时, 就有可能让cnt减出问题, 比如多减了一下, 或者少减了一下。 

        所以, 我们的cnt不能随意地减减, 所以这里就有了一个概念——申请计数器, 本质是对计数器减减, 这个操作在信号量当中专门封装了一个方法, 就好比这个信号量类里面有一个计数器成员, 申请的时候就有一个成员方法——申请信号量, 对信号量做减减, 这个操作就可以成为p操作。 ——释放资源, 就好比释放信号量, 本质是对计数器进行++操作。 并且这个操作表示归还资源, 因为加加资源变多了, 就表示归还资源。 归还资源, 其他进程就可以申请了, 这个操作, 就叫做v操作。 ——信号量的申请和释放, 就被我们叫做pv操作。 ——其中, 这些操作, 在汇编层面上就会将我们的语句c语句变成多条汇编语句, 所以多执行流调度的时候, 一定会已出现多执行流混合交叉的问题, 就可能这个变量出现问题。 ——所以, 这里就需要我们我们申请和释放的这个pv操作必须是原子的。 ——什么是原子的? 在技术层面上来说, 如果一条语句转化为汇编语句, 只有一条汇编语句, 那么就是原子的。 

        所以, 通过以上的论述, 我们就能总结出一个结论。——就是对于信号量来说, 信号量本质就是一把计数器, 对于计数器匹配的操作, 就叫pv操作, 这个pv操作是原子的。 所有的执行流申请资源, 就必须先申请信号量资源, 得到信号量之后, 才能访问临界资源。 如果信号量的值为1/0两态的, 我们就称为二元信号量, 就是互斥。 其中, 我们申请信号量的本质, 就是对临界资源的预定机制!!!

信号量接口

        信号量接口博主没有具体学习过, 这里不讲解具体, 只是提一下

        其中第二个参数是申请多个信号量, 多个信号量和信号量是几, 是不一样的概念。 

 

        上面的参数中有一个结构体叫做sembuf, 这个结构体如下:

 信号量与进程间通信

        信号量为什么是进程间通信的一种?

  •         1、我们的通信, 不仅仅是传送数据, 通信也在于双方之间的互相协同。 
  •         2、协同虽然不是以传送数据为目的。 但是他以时间通知为目的。 它的本质就是在传递信息, 只不过不是传统的hello world、hello linux这样的数据了。 ——就比如我们上课, 以及我们吃饭, 假如小王和校长, 小张吃饭的时候喜欢和小王吃, 所以小王吃饭的时候就会给小张打电话。 小王喜欢逃课, 小张在上课的时候, 如果有签到, 就给小王打电话。 这两个人互相通知, 这个互相就叫做协同;这个通知, 就叫做信号。 这个通知是不是通信?是的!!!——所以,信号量的本质, 其实也是通信。

——————以上就是本节全部内容哦, 如果对友友们有帮助的话可以关注博主, 方便学习更多知识哦!!!同时对于本节内容, 博主整理了笔记图片, 友友们可以保存方便查阅哦:

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

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

相关文章

构建未来企业的理论基石:业务能力建模指南的深度解析与战略实施框架

数字化转型已经成为全球企业的战略焦点&#xff0c;在这个过程中&#xff0c;如何有效地将复杂的业务需求、技术架构和市场变化结合&#xff0c;形成具备长期竞争力的企业能力框架&#xff0c;是企业成败的关键。《业务能力指南》提供了一套经过验证的理论体系&#xff0c;帮助…

【番茄成熟度数据集】12类names

【番茄成熟度数据集】12类 names: [half-ripe, ripe, rotten tomatoes, tomato fully ripe, tomato semi ripe, tomato unripe, tomato_half_ripe, tomato_overripe, tomato_ripe, tomato_rotten, tomato_unripe, unripe] 名称: [半熟的, 成熟的, 腐烂的西红柿, 西红柿完全成熟…

centos7离线安装MySQL8

下载Mysql安装包地址 https://dev.mysql.com/downloads/mysql/解压到指定目录 [rootlocalhost tools]# tar -xvf mysql-8.4.2-1.el7.x86_64.rpm-bundle.tar -C /root/training [rootlocalhost tools]# cd ../training/ [rootlocalhost training]# ll total 1027204 -rw-r--r-…

计算机毕业设计之:基于微信小程序的诗词智能学习系统(源码+文档+解答)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

Spring_AMQP

文章目录 一、SpringAMQP二、SpringAMQP应用2.1、消息发送2.2、消息接收 一、SpringAMQP SpringAMQP是基于RabbitMQ封装的一套模板&#xff0c;并且还利用SpringBoot对其实现了自动装配&#xff0c;使用起来非常方便。 SpringAmqp的官方地址。 SpringAMQP提供了三个功能&am…

PMP--二模--解题--51-60

文章目录 14.敏捷--术语表--完成的定义DoD--它是团队需要满足的所有标准的核对单&#xff0c;只有可交付成果满足该核对单才能视为准备就绪可供客户使用。51、 [单选] 在冲刺计划会议上&#xff0c;Scrum主管重申&#xff0c;如果在冲刺结束时敏捷项目团队正在构建的产品增量没…

Linux:进程(四)

目录 一、进程优先级 二、Linux调度与切换 1.背景 2.进程切换 3.Linux调度 一、进程优先级 背景&#xff1a;在计算机中&#xff0c;软硬件资源是有限的&#xff0c;而进程想要访问某一种资源&#xff0c;就得通过排队来保证访问资源的过程是有条不紊的。 Linux下对优先级…

华为HarmonyOS灵活高效的消息推送服务(Push Kit) - 1 简介

Push Kit&#xff08;推送服务&#xff09;是华为提供的消息推送平台&#xff0c;建立了从云端到终端的消息推送通道。所有HarmonyOS应用可通过集成Push Kit&#xff0c;实现向应用实时推送消息&#xff0c;使消息易见&#xff0c;构筑良好的用户关系&#xff0c;提升用户的感知…

Django 请求配置

http请求配置 请求流程 urls.py配置 from first_app import viewsurlpatterns [path(admin/, admin.site.urls),path(test/,views.first_test), ] views.py配置 from django.shortcuts import render,HttpResponse# Create your views here. def first_test(request):prin…

FLUX.1 ComfyUI:专属图像生成助手

FLUX.1 & ComfyUI&#xff1a;专属图像生成助手 FLUX.1 简介 FLUX.1 是由 黑森林实验室 (Black Forest Labs) 开发的一款高性能图像生成模型&#xff0c;分为以下三个版本&#xff1a; FLUX.1-pro (闭源): 最顶级的版本&#xff0c;具备极高的图像生成能力&#xff0c;支…

Python办公自动化教程(001):PDF内容提取

1、Pdfplumber介绍 pdfplumber的github地址&#xff1a; https://github.com/jsvine/pdfplumber/【介绍】&#xff1a;pdfplumber 是一个用于处理 PDF 文件的 Python 第三方库&#xff0c;它提供了一种方便的方式来提取 PDF 文件中的文本、表格和其他信息。【功能】&#xff…

2、StarGAN V2

2、StarGAN V2 StarGAN 论文链接&#xff1a;StarGAN StarGAN V2 论文链接&#xff1a;StarGAN V2 在介绍StarGAN V2之前&#xff0c;我们先对StarGAN有一定的了解&#xff0c;StarGAN V2只是在StarGAN的基础上做出了改进&#xff0c;基本的架构是没有变的&#xff0c;只是将…

SQL - 进阶语法(二)约束

1. SQL约束 约束用于约束表中的数据规则&#xff0c;如若存在违反行为&#xff0c;行为会被约束终止。 • NOT NULL 确保列不能有NULL值 如果添加一行新的数据&#xff0c;不能有null值&#xff0c;否则无法添加 新建表格 CREATE TABLE new_table( ID int NOT NULL, NAME …

尚品汇-自动化部署-Jenkins的安装与环境配置(五十六)

目录&#xff1a; 自动化持续集成 &#xff08;1&#xff09;环境准备 &#xff08;2&#xff09;初始化 Jenkins 插件和管理员用户 &#xff08;3&#xff09;工作流程 &#xff08;4&#xff09;配置 Jenkins 构建工具 自动化持续集成 互联网软件的开发和发布&#xf…

zynq中断

通用中断控制器的作用&#xff1a; 它是一个中央处理中心&#xff0c;用于管理来自处理器核心&#xff08;PS&#xff09;和外设&#xff08;PL&#xff09;的中断。它可以启用、禁用、屏蔽和设置中断源的优先级。 中断处理流程&#xff1a; 所有中断源首先被集中到控制器。控…

AI模型对比研究员创意

大语言模型可以接受训练&#xff0c;完成许多任务。其中最广为人知的用途之一是作为生成式人工智能&#xff1a;当收到提示或被问到问题时&#xff0c;它们可以生成文本作为答复。例如&#xff0c;公开的大语言模型 ChatGPT 可以根据用户输入生成文章、诗歌和其他文本形式。 任…

C语言题目之单身狗2

文章目录 一、题目二、思路三、代码实现 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、题目 二、思路 第一步 在c语言题目之打印单身狗我们已经讲解了在一组数据中出现一个单身狗的情况&#xff0c;而本道题是出现两个单身狗的情况。根据一个数…

查询 B 站注册时间

有时候想看看自己玩 B 站多少年了&#xff0c;想知道自己什么时候注册的。 此外&#xff0c;据说注销 B 站账户的话也得提供详细注册日期。 ‍ 通过创作中心查看 登录网页版 B 站&#xff0c;点击右上角的创作中心&#xff0c;然后就能看到在 B 站多少天了&#xff1a; ​…

基于JAVA+SpringBoot+Vue的医院资源管理系统

基于JAVASpringBootVue的医院资源管理系统 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1f345; 哈…

Qt开发技巧(七)动态换图,QVideoWidget视频闪烁,Qt日志打印,系统消息处理,编译前后的操作,QSettings配置文件,屏幕自适应

1.动态换图 Qt开发时&#xff0c;有时候我们在界面上需要动态的切换图片&#xff0c;比如接到来自底层驱动的信号分成告警信号&#xff0c;正常信号&#xff0c;危险信号&#xff0c;在界面上使用QLabel通过贴图来表示不同的信号&#xff0c;这时候尽量使用setStyleSheet()&…