学习系统编程No.20【进程间通信之命名管道】

news2024/11/18 1:46:33

引言:

北京时间:2023/4/15/10:34,今天起床时间9:25,睡了快8小时,昨天刷视屏刷了一个小时,本来12点的时候发完博客洗把脸就要睡了,可惜,看到了一个标题,说实话,现在的标题党是懂人性的,接下来就是无法自拔的一个小时快乐时光,但导致莫名间接熬夜,你说烦人不烦人!但是不怕,这个星期5天,几乎没有摆烂,只要今天和明天不摆烂 ,这个星期就是成功滴,一想美滋滋!所以让我们抓紧进入今天的学习吧! 今天我们就正式学习有关内存共享的知识,当然还有管道遗落的知识,因为管道真的是太经典了,但是前提是,现在我要去把我的被单和毯子给晒一晒,不然晚上无法舒舒服服的睡觉啦!并且由于昨天买的羽毛球拍到了,所以下午是打羽毛球的快乐时光,所以该篇博客,今天能不能发,是未可知的!

在这里插入图片描述

回顾管道控制进程

之前开始学习进程间通信的时候,我们就学习了如何使用管道来进行进程间通信,了解了通过一个管道进行进程间通信之后,我们又通过管道的读写规则了解了"血缘关系"进程之间的通信方法,此时我们通过一个 很经典的通信方式(当管道中没有数据的时候,对应读取数据的进程只能等待对应写数据的进程) ,所以通过这一重要的读写原理,此时我们就设计出了进程控制的结构一个进程(常常是父进程)通过创建多个管道和子进程,然后向对应的管道中写入数据,进而控制与该管道文件匹配的子进程,所以明白了这个原理之后,此时就可以进行具体的编码和优化,最终得到了上篇博客所示的进程控制代码,但是该代码中,还存在一个很隐蔽的问题,上篇博客,我们没有进行详细的讲解,所以在这里,我们进行补充讲解,如下:

回收子进程

1.让子进程退出

从进程控制代码中(上篇博客),我们看出,当我们构建好了进程控制代码,可以让父进程通过对管道文件的读写规则同时去控制子进程完成不同的任务时,在最后任务完成结束,代码要退出时,我们是需要将子进程进行回收(因为子进程占用的是内存上的空间,避免内存泄露),所以此时在回收子进程的问题上,就存在那个很隐蔽的问题,此时我们就需要解决这个问题,如下:

想要解决这个问题,首先明白一点,就是如何让子进程退出,这点想必大家都很清楚(上篇博客详细介绍了),想要让一个子进程退出(场景:上篇博客代码,子进程读取管道文件,父进程向管道文件写入),只要让父进程无法向对应子进程的管道文件中写入数据,此时操作系统就会因为不允许资源浪费,使 用13号信号,让子进程退出,所以让一个子进程退出,就是将对应管道文件的写端关闭就行

明白了这点,此时我们距离解决这个隐蔽问题就剩下一个现象,看到了这个现象,此时一切都是So,So,如下图所示:
在这里插入图片描述

如上图所示,明白到了,除了第一次循环的子进程是只继承了一个写文件描述符,其它子进程的写文件描述符都是在累加,所以导致除了最后一次循环创建的那个管道文件的写端只有父进程指向之外(因为最后一次循环子进程为了构建单向信道,需要把写端关闭),其它的管道文件都被除了父进程以外的一个或多个进程以写的方式指向(如上图,第五次循环之后的子进程,此时对前面创建的4个管道文件的写端都有写入的能力),具体如下图所示:
在这里插入图片描述
所以上图的第一个管道文件的写端由于被不止一个进程打开,所以此时单单只是将父进程对应的写端关闭,还有剩下多个子进程可以向该管道文件写入数据,所以此时操作系统并不会使用13号信号,将该子进程退出,所以最好的解决方法就是如上图所示:
从后向前关闭父进程对应管道文件的写端,这样就可以让子进程挨个退出了,进而最终达到回收子进程的目的

有关上述现象图的继承理解
注意: 在常见的操作系统中,当子进程从父进程中继承文件描述符表时,子进程会得到指向同一文件表项的新的文件描述符副本(继承),关闭一个文件描述符只会减少该文件描述符所指向的文件表项的引用计数,如果仍然有其他文件描述符指向该文件表项,则该文件表项仍然存在;因此,无论父进程关闭其中的一个文件描述符或者两个,当子进程从它那里继承文件描述符表时,子进程都会得到对这两个打开文件的文件描述符

总结: 只要父进程分别以读写的方式打开了同一文件,创建了两个文件描述符,那么此时无论父进程是关闭一个文件描述符,还是两个都关闭,此时由于子进程继承了父进程pcb大部分的内容,并且因为进程间具有独立性,所以此时操作系统检测都父进程将要关闭文件描述符的时候(也就是修改数据的时候),就会进行写实拷贝(在内存中重新开辟一个空间给父进程去修改数据),所以导致子进程中继承的父进程pcb是不会被改变,所以子进程任然可以分别继承以读写方式打开的两个文件描述符

2.等待僵尸状态的子进程

明白了上述知识点之后,此时就可以明白除了最后一次循环创建的管道文件只被一个进程以写的方式打开之外,其它的管道文件都是同时被两个或者两个以上的进程以写的方式打开(父进程和子进程),所以最好的方法就是从后向前将父进程对应管道文件的写端关闭,此时所有的子进程就被很好的关闭了,所以当子进程被关闭之后,此时最后一步就是将处于僵尸状态的子进程回收(waitpid),具体代码如下:
在这里插入图片描述
具体现象如下:
在这里插入图片描述
在这里插入图片描述
所以此时因为进程控制创建出的被控制进程和创建的管道文件就都被关闭和回收啦!利用管道控制进程的代码就大功告成啦! 具体代码贴在该博客最后(虽然上篇博客中有)

深入进程控制结构

通过上述的知识,我们知道,我们可以很好的利用进程间通信的知识和模板去构建出一个进程控制的结构,并且这个结构中存在的问题(上述问题),因为子进程会继承上一进程打开的所有文件描述符,导致一个子进程同时具有多个读端和写端,此时根据这个现象,就会存在很多的问题,不仅仅只是上述回收子进程的时候需要从后向前回收,更重要的是 ,此时还有引起另一个严重问题,就是后一个子进程也可以向前一个管道文件中写入数据,有甚者更是可以向多个管道文件中写入数据(虽然因为没有特定的文件描述符,子进程并不能写入,但是为了防止),所以需要避免这个问题,此时我们就可以通过将代码结构进行一定的改变,进而真正的构建出像进程间通信一般的单向信道,如下:

原理:本质上,在实现上述进程控制的前提下,让每一个管道和进程之间都互不干扰,实现单向通信是不难的,实际从问题出发,就是要解决子进程继承父进程文件描述符时,多余进程的文件描述符而已,所以此时我们只需要再创建一个数组,用这个数组专门来保存父进程创建的写端文件描述符,得到父进程所有的写端文件描述符,然后把这个数组中的数据拿给子进程使用,间接在子进程中遍历这个数组,并且使用close关闭子进程继承的文件描述符表中对应数组下标对应的写端文件描述符,这样子进程中多余进程到的写端文件描述符就被全部关闭,最终真正的实现单向信道进程控制结构

具体代码实现如下:
在这里插入图片描述

命名管道

无论是之前的进程间数据传送的知识,还是上述进程控制的知识,本质上都只是在利用管道进行而已,准确的来说也就是利用一个内存级的文件而已,并且要明白,此时的这个管道是使用系统调用接口 pipe 来创建的,所以本质上这个管道文件是操作系统给我们提供的,我们是摸不着,看不到的,所以准确的来说,我们之前学习的进程数据传送和进程控制利用的管道都是匿名管道,一个由内核创建,操作系统管理的文件

并且还可以得出一个结论,我们一直利用的都是具有"血缘关系"的进程可以继承同一文件描述符的特性和同时以读写方式打开同一匿名管道文件进行学习有关进程间通信的知识,此时提出问题:那么如果是两个完全没有关系的进程,此时进程间还可以进行通信吗?首先答案是可以的,不然它怎么能叫进程间通信呢?就应该叫血缘关系进程进程间通信了,具体如下述所说:

如何创建命名管道

首先明白,想要让两个不同的进程支持相互通信,那么此时就不可以使用匿名管道,而要用命名管道,所以下面第一个知识点,我们就来了解一下命名管道的创建,注意:命名管道的创建区别于匿名管道的创建,它不仅可以直接使用命令行创建,指令:mkfifo filename,也可以使用系统调用创建,调用接口:int mkfifo(const char *filename,mode_t mode);基本使用:mkfifo("filename", 0644);具体使用方式如下图所示:
在这里插入图片描述
通过上图中对 mkfifo 系统调用接口的描述,此时我们就可以知道,该接口的功能就是用来创建一个命名管道,头文件为#include<sys/types.h>,#include<sys/stat.h>等具体使用方式,此时我们就可以很好的自己创建一个命名管道出来啦!

注意: 虽然,mkfifo是创建一个文件,并且这个文件不像是匿名管道文件一样是由内核创建的内存级文件(不占用磁盘空间),并且该文件是位于文件系统中,但该文件却并不对应任何物理磁盘上的文件,而只是在内存中分配一个空间来存储不同进程之间进行进程间通信时的读取或写入的数据而已(类似于文件对象自带的缓冲区),所以从这个意义上来说,我们可以将mkfifo创建的文件视为一种内存级文件,因为它们的存在仅限于进程之间的通信,当进程间完成通信之后,回收进程时,此时由于它们的生命周期与它们关联的进程相同,所以当这些进程终止时,这些文件也会被自动删除,所以本质上命名管道文件就是一个内存级缓冲区文件!

得出结论: 使用 mkfifo 创建的文件并不会占用磁盘空间,因为它只是一个命名管道(内存级文件),只有在进程进行通信时,也就是一个进程打开一个命名管道并向其中写入数据,另一个进程打开同一个命名管道并从中读取数据,此时才会产生实际的数据传输和占用磁盘空间,否则执行 mkfifo 命令只会在文件系统中创建一个新的文件节点,并不会分配任何实际的磁盘空间

管道文件类型:
在这里插入图片描述
对文件类型和文件属性感兴趣的同学可以参考该链接博客:文件类型详解

文件类型
普通文件 -
目录文件 d
链接文件 l
块设备 b
字符设备 c
管道文件 p
套接字文件 s

深入命名管道

搞定了上述有关命名管道文件的知识,此时我们就可以具体的来看一看,是如何利用命名管道实现不同进程之间的通信了,如下图所示:
在这里插入图片描述
如上图所示:此时我们就构建出了一个和构建父子进程间通信结构类似的模板,此时按照这个原理,我们就可以进行代码的编写啦!简单理解就是两个进程打开了同一个文件,一个进程以读的方式打开,一个进程以写的方式打开,本质能够通信还是因为,操作系统为了节约资源,所有进程共享同一个已经打开的文件,而不是重复打开,并且 注意, 如果我们想要让不同的两个进程打开同一个文件,此时就需要让它们根据同一路径去寻找该对应文件**,所以只要让不同的进程通过文件路径和文件名看到同一文件,并打开,这就是两个不同进程看到同一份资源的前提,也就是进程间通信的前提!

代码实现

原理: 1.创建一个管道文件 2.让读写端进程分别按照自己的需求打开文件 3.开始通信

首先创建两个文件,一个serves.cpp,一个client.cpp,用来分别表示两个不一样的进程,具体代码如下:

serves.cpp文件

在这里插入图片描述
client.cpp文件

在这里插入图片描述

command.hpp共享文件

在这里插入图片描述
两个进程代码通信现象:
在这里插入图片描述
如上图所示,此时一个进程就可以很好的把数据传送给另一个进程,也就类似于一个用户端可以把数据传送给服务端

总:明白了使用匿名管道的进程控制,玩一个命名管道So,So!

在这里插入图片描述

总结:快乐生活每一天,有关管道的知识就这样了吧!

使用匿名管道进行进程控制代码如下:

在这里插入图片描述

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

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

相关文章

.Net路由操作!!!!

什么是路由 问题 答案 路由是什么&#xff1f; 路由系统负责处理传入的请求并选择控制器和操作方法来处理它们。 路由系统还用于在视图中生成路由&#xff0c;称为传出的URL 路由有什么用&#xff1f; 路由系统能够灵活地处理请求&#xff0c;面不是将URL与Visual Studio…

MySQL(31)-ubuntu20.04-下安装mysql5.7

ubuntu20.04 下apt 默认安装的是8.0版本&#xff0c;如果要安装5.7版有如下3种方式&#xff1a; 1 下载 MySQL 二进制压缩包&#xff0c;解压并设置相关的参数即可运行 2 通过命令 apt install 进行安装&#xff0c;先下载 MySQL 5.7 对应的源&#xff0c;然后执行安装命令 ap…

5 分钟带你小程序入门 [实战总结分享]

微信小程序常常用 4 种文件类型 JS 文件 JS 在小程序中用于编写页面逻辑和交互效果&#xff0c;可调用 API 接口完成数据请求和处理&#xff0c;也可以使用第三方库和框架。 模块化编程&#xff1a;小程序中JS文件可以使用ES6的模块化语法&#xff0c;通过export和import来…

【vue3】关于watch与computed的用法看这个就ok

&#x1f609;博主&#xff1a;初映CY的前说(前端领域) ,&#x1f4d2;本文核心&#xff1a;watch()与computed的使用【vue2中watch|computed概念详解】&#xff0c;本文将介绍在vue3中怎么使用这两者技能 【前言】vue2当中有这两个技能&#xff0c;那么vue3中的watch与compute…

【云原生进阶之容器】第六章容器网络6.4.1--Flannel组网方案综述

《云原生进阶之容器》专题索引: 第一章Docker核心技术1.1节——Docker综述

【Unity】用HDRI作为Unity的Skybox

教程&#xff1a;用HDRI作为Unity的Skybox 在Unity中&#xff0c;Skybox是用于创建环境背景的一种组件。使用高动态范围图像&#xff08;HDRI&#xff09;作为Skybox可以提供更真实的环境背景。以下是使用HDRI作为Unity Skybox的步骤&#xff1a; 步骤1&#xff1a;下载HDRI图…

进销存管理系统能为企业带来哪些实际效益?

随着互联网的不断发展&#xff0c;如今的商业世界已经越来越向数字化转型。拥有一套完整的数字化的进销存管理能够极大地提升公司货物进出库存情况的效率和准确性&#xff0c;避免过程中出现不必要的错误和漏洞&#xff0c;从而帮助企业更加稳健地自我发展。那么&#xff0c;一…

华为MatePad有什么好用的软件?

现如今伴随着办公方式的转变&#xff0c;人们正迫切地寻找能够顺应时代的“生产力新工具”&#xff0c;它既要能够满足线上/线下灵活切换&#xff0c;又要具备绘画、键入、远程沟通、跨终端联动等多种功能。 对大多数人来说&#xff0c;日常使用华为平板只是满足一下娱乐和生活…

【SSA-LSTM】基于麻雀算法优化LSTM 模型预测研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

超详细从入门到精通,pytest自动化测试框架实战-fixture固件高级操作(十一)

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 参数化fixture fix…

深度学习随笔

一、SPP的作用 解决了训练CNN需要输入图像尺寸一致的问题。 一个CNN可看作由卷积、池化、全连接层组成&#xff0c;由于全连接层的权重矩阵是一个固定值&#xff0c;因此输入全连接层的特征图的维度也必须固定。 SPP利用多尺度思想解决了上述问题&#xff0c;使得神经网络的训练…

2023/4/16总结

深刻的了解了网络编程的一些知识点 socket:套接字 ServerSocket 用来声明服务器 Socket用来声明客户端&#xff0c;其实也不然&#xff0c;在serversocket的accept的方法中&#xff0c;返回的是一个socket变量。我觉得更像一个接口&#xff0c;网络接口。 InternetAddress可以…

PaddlePaddle NLP学习笔记1 词向量

文章目录1.语言模型 Language Model1.1 语言模型是什么1.2 语言模型计算什么1.3 n-gram Language Model2.神经网络语言模型NNLM2.1 N-gram模型的问题3. 词向量3.1 词向量(word Embedding)word2vec 词向量训练算法3.2 如何把词转换为词向量&#xff1f;3.3如何让向量具有语义信息…

Windows 下部署Redis 主从模式+哨兵模式+JAVA连接方式

前言 之前项目需求部署redis高可用&#xff0c;走了很多弯路以及相关配置来回折腾浪费了很多时间&#xff0c;特地记录下。 主从模式&#xff1a;实现多台redis实例进行服务运行&#xff0c;并且数据相互同步&#xff1b; 哨兵模式&#xff1a;实现主服务器和从服务器进行监听…

工业电子中的安森美深力科AMIS30660CANH2RG CAN收发器 面向工业自动化和汽车电源应用

工业电子中的安森美深力科AMIS30660CANH2RG CAN收发器 面向工业自动化和汽车电源应用 AMIS30660CANH2RG CAN 收发器是控制器区域网络 (CAN) 协议控制器和物理总线之间的接口&#xff0c;可在 12 V 和 24 V 系统中使用。该收发器为总线提供差分发射功能&#xff0c;向 CAN 控制…

Spark编程基础-RDD

目录 1.何为RDD 2.RDD的五大特性 3.RDD常用算子 3.1.Transformation算子 1.map() 2.flatMap() 3.reduceByKey() 4 . mapValues() 5. groupBy() 6.filter() 7.distinct() 8.union() 9.join() 10.intersection() 11.glom() 12.gruopBykey() 13.sortBy() 14.sortByKey …

docker+docker-compose+nginx前后端分离项目部署

文章目录1.安装docker1.1 基于centos的安装1.2 基于ubuntu2.配置国内加速器2.1 配置阿里云加速器&#x1f340; 找到相应页面&#x1f340; 创建 docker 目录&#x1f340; 创建 daemon.json 文件&#x1f340; 重新加载服务配置文件&#x1f340; 重启 docker 引擎2.2 配置网易…

OJ系统刷题 第八篇

13415 - 津津的储蓄计划 时间限制 : 1 秒 内存限制 : 128 MB 津津的零花钱一直都是自己管理。每个月的月初妈妈给津津300元钱&#xff0c;津津会预算这个月的花销&#xff0c;并且总能做到实际花销和预算的相同。 为了让津津学习如何储蓄&#xff0c;妈妈提出&#xff0c;津…

计算机组成原理---第四章 指令系统

一、指令系统的发展与性能要求 指令系统的概述 指令就是要计算机执行某种操作的命令。可分为&#xff1a;①微指令&#xff0c;属于硬件&#xff1b;②机器指令&#xff0c;简称指令&#xff0c;完成算术逻辑操作&#xff1b;③宏指令&#xff0c;由若干条机器指令组成&#xf…

[Java]JSTL标签库

EL表达式https://blog.csdn.net/m0_71229255/article/details/130173486?spm1001.2014.3001.5501 JSTL标签的使用 Java Server Pages Standard Tag Libray(JSTL): JSP标准标签库&#xff0c;是一个定制标签类库的集合&#xff0c;用于解决一些常见的问题&#xff0c;例如迭代…