【Linux】IPC:匿名管道、命名管道、共享内存

头像
⭐️个人主页:@小羊
⭐️所属专栏:Linux
很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~

动图描述

目录

  • 1、管道
  • 2、进程池
  • 3、命名管道
  • 4、共享内存


1、管道

我们知道进程具有独立性,但是在一些场景中进程间也需要通信,那怎么实现进程间的通信呢?

进程间通信的核心是:由OS提供一份公共的内存资源。

进程间通过文件的内核缓冲区实现资源共享,这个过程并不需要磁盘参与,所以设计了一种内存级的文件来专门实现进程间通信,这个内存级文件就是管道。
什么是管道?

  • 管道是Unix中最古老的进程间通信的形式
  • 从一个进程连接到另一个进程的一个数据流称为一个“管道”

管道的原理:

管道只能进行单向通信。

必须要先打开文件,再创建子进程,不能先创建子进程,再打开文件。这个过程利用的是子进程会继承父进程相关资源的特性。

  • 为什么父进程打开文件的时候必须要以“读写”方式打开,不能只读或只写?
    因为父进程打开文件,创建子进程后,父子进程必须有一个写,一个读,不能两个都读或两个都写。

管道不需要路径,也就不需要名字,所以叫做匿名管道。

在这里插入图片描述

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;int main()
{//1、创建管道int fds[2] = {0};int n = pipe(fds);if (n != 0){cerr << "pipe error" << endl;return 1;}//2、创建子进程pid_t id = fork();if (id < 0){cerr << "fork error" << endl;return 2;}else if (id == 0){//子进程//3、关闭不需要的fdclose(fds[0]);//0是读exit(0);}else{//父进程close(fds[1]);//1是写pid_t rid = waitpid(id, nullptr, 0);if (rid > 0){cout << "father wait child success, id :" << rid << endl;}}return 0;
}

上面的操作只是让父子进程看到了同一份资源,但还没有实现通信。这个内存资源有OS提供,所以进程间通信也理应通过操作系统实现,也就是调用系统调用。

	//...else if (id == 0){//子进程//3、关闭不需要的fdclose(fds[0]);//0是读int cnt = 0;while (true){string message = "hello world, hello ";message += to_string(getpid());message += ", ";message += to_string(cnt++);write(fds[1], message.c_str(), message.size());sleep(1);}exit(0);}else{//父进程close(fds[1]);//1是写char buffer[1024];while (true){ssize_t n = read(fds[0], buffer, 1024);if (n > 0){buffer[n] = 0;cout << "child->father, message: " << buffer << endl;}}pid_t rid = waitpid(id, nullptr, 0);if (rid > 0){cout << "father wait child success, id :" << rid << endl;}}//...
  • 子进程写,父进程读。看待父子进程,就像看待文件一样。

在上面子进程sleep的过程中,父进程在做什么呢?在阻塞等待。
父进程在读完了子进程的数据后,OS就不要父进程读了,让其进入阻塞状态,等待子进程再次写入。这是为了保护共享资源,防止子进程写了一半父进程就读,或者父进程读了一半子进程就写。这个过程是管道内部自己做的。

现象:

  1. 管道为空&&管道正常,read会阻塞(read是一个系统调用)。
  2. 管道为满(管道资源是有限的)&&管道正常,write会阻塞。
  3. 管道写端关闭&&读端继续,读端读到0,表示读到文件结尾。
  4. 管道读端关闭&&写端继续,OS杀掉写入的进程。

在这里插入图片描述

特性:

  1. 面向字节流。不关心对面是如何写的,按需读取。
  2. 用来进行具有血缘关系的进程,进行IPC,常用于父子。
  3. 文件的声明周期随进程,管道也是。
  4. 单向数据通信。
  5. 管道自带同步互斥等保护机制。

2、进程池

退出进程池
当关闭写端,读端读到0,表示读到文件结尾,则结束进程。即将父进程所有的读端关闭,则相应的子进程就会结束,最后再由父进程等待回收。

void CleanProcessPool()
{//virsion1for (auto &c : _channels){c.Close();}for (auto &c : _channels){pid_t rid = waitpid(c.GetId(), nullptr, 0);if (rid > 0){cout << "child: " << rid << "wait...success" << endl;}}
}

:上面关闭读端和等待子进程为什么要分开,关一个等待一个行吗?

在这里插入图片描述

根据上面的分析,所有的子进程的file_struct都会指向第一个管道,越往后的子进程指向的管道越多。所以我们只是把masterfile_struct中指向管道关闭,这个管道还有其他子进程的file_struct指向,因此读端不会读到0,子进程不会退出,就会一直阻塞。解决这个问题有两种办法:

1、倒着关闭
因为通过分析可知,越早创建的管道指向越多,最后一个管道只被指向一次,只要将最后一个进程关闭,则前面的所有管道被指向都会少1,因此倒着关闭就不会出现阻塞的问题。

//virsion2
for (int i = _channels.size()-1; i >= 0; i--)
{_channels[i].Close();pid_t rid = waitpid(_channels[i].GetId(), nullptr, 0);if (rid > 0){cout << "child: " << rid << "wait...success" << endl;}
}

2、在子进程中关闭所有历史fd
因为父进程的3号文件描述符总为空,子进程只有3号文件描述符指向管道。在这之前子进程继承父进程对之前的管道的指向,所以只需要在子进程中把这些指向全部关掉就行。

在这里插入图片描述

// 3、建立通信信道
if (id == 0)
{//关闭历史fdfor (auto &c : _channels){c.Close();}// 子进程//close(pipefd[1]);//dup2(pipefd[0], 0); // 子进程从标准输入读取//_work();//exit(0);
}

3、命名管道

我们知道了,匿名管道的原理,是让父子进程看到同一份资源,而父子进程看到同一份资源,是因为子进程继承了父进程的资源。所以不难得出,匿名管道两端必须是父子进程。而如果我们想在任意进程之间建立管道呢?首先可以肯定的是这任意两个进程之间也要能看到同一份资源,因为是任意进程之间所以这个资源不能继承而来,所以就牵扯出了命名管道

匿名管道是内存级的虚拟文件,而命名管道是真实存在的文件。

在这里插入图片描述
在这里插入图片描述

可以看到管道文件fifo的大小依旧为0,所以两个进程间通信的数据并没有刷新保存到磁盘中。

  • 命名管道的原理:
    为什么叫做命名管道,因为有名字,是真实存在的文件,既然是真实存在的文件,就一定有路径+文件名,而路径+文件名具有唯一性。这样不同的进程可以用同一个文件系统路径标志同一个资源,也就是不同的进程看到了同一个资源。

  • 命名管道和普通文件的区别:
    这么看来命名管道和普通文件好像除了创建方式不同外也没多大区别,而普通文件好像也能实现进程间通信,但是普通文件有两个问题,我们往普通文件中写入的数据会被刷新到磁盘中保存,另外普通文件也没有被特殊保护,也就是我们可以往里写大量的数据,在写的过程中也有可能被其他进程读,这两个问题是命名管道需要重点处理的,所以命名管道和普通文件有很大的区别,是特殊设计的。

  • 这个命名管道,该由谁创建?
    公共资源:一般要让指定的一个进程现行创建。一个进程创建&&使用,另一个进程获取&&使用。


4、共享内存

共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。
在这里插入图片描述

  • 共享内存 = 共享内存的内核数据结构 + 内存块。

  • 让两个进程通过各自的虚拟地址空间,映射同一块物理内存,叫做共享内存。共享内存的本质还是让不同的进程看到同一个资源。

在这里插入图片描述

  • IPC_CEEAT:单独使用,如果shm不存在则创建,如果存在则获取。保证调用进程就能拿到共享内存。
  • IPC_CEEAT | IPC_EXCL:组合使用,如果不存在则创建,如果存在则返回错误。只要成功,一定是新的共享内存。

key为什么必须要用户传入,为什么内核自己不生成?

  1. 任意进程间是独立的,由某一个进程内生成key,其他的进程是拿不到的。
  2. 理论上用户可以随意设置key,只要保证不冲突就可,为了保证key的唯一性有函数来减小冲突的概率。

在这里插入图片描述

定义全局的key,让进程间通过绝对路径都能看到,由某个进程设置进内核中,则其他进程也能够得到。
所以在应用层面,不同进程看到同一份共享内存是通过唯一路径+项目ID来确定的,类似命名管道也是通过文件路径+文件名来确定的。

在这里插入图片描述

在OS看来,由shmget函数创建的共享内存是OS创建的,所以共享内存的生命周期随内核。 和文件不同,文件的生命周期随进程。所以共享内存一旦创建出来,要么由用户主动释放,要么OS重启。

共享内存的管理指令:

  • ipcs -m:查看共享内存信息
  • ipcrm -m shmid:删除共享内存

需要注意的是,删除共享内存只能通过shmid删除,不能通过key删除。

shmid VS key:

  1. shmid:仅供用户使用的shm标识符(类似文件描述符fd)
  2. key:仅供内核区分不同shm唯一性的标识符(类似文件地址)

除了指令删除shm,还可以通过函数删除:

在这里插入图片描述

共享内存也有权限。

栈区、堆区、共享区等地址空间,是用户空间,我们不需要调用系统调用就可以直接使用。

| 共享内存的特点:

  • 不需要调用系统调用,通信速度快。
  • 让两个进程在各自的用户空间共享内存块,是真正的共享资源,但是不像管道,共享内存没有任何保护。
  • 共享内存的保护机制,需要用户自己完成。

在这里插入图片描述


本篇文章的分享就到这里了,如果您觉得在本文有所收获,还请留下您的三连支持哦~

头像

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python生成图片和pdf,快速

1、下载安装 pip install imgkit pip install pdfkit2、wkhtmltopdf工具包&#xff0c;下载安装 下载地址&#xff1a;https://wkhtmltopdf.org/downloads.html 3、生成图片 import imgkit path_wkimg rD:\app\wkhtmltopdf\bin\wkhtmltoimage.exe # 工具路径&#xff0c;安…

location的使用规则

1、基于URL的location 负责均衡配置 后端集群中的web服务器&#xff0c;必须要有对应的目录和文件才能被访问到 http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;upstream default_pool {server 10.0.0.7:…

ComfyUI实现老照片修复——AI修复老照片(ComfyUI-ReActor / ReSwapper)解决天坑问题及加速pip下载

AI修复老照片&#xff0c;试试吧&#xff0c;不一定好~~哈哈 2023年4月曾用过ComfyUI&#xff0c;当时就感慨这个工具和虚幻的蓝图很像&#xff0c;以后肯定是专业人玩的。 2024年我写代码去了&#xff0c;AI做图没太关注&#xff0c;没想到&#xff0c;现在ComfyUI真的变成了工…

基于C++的DPU医疗领域编程初探

一、大型医院数据处理困境与 DPU 的崛起 在数字化浪潮的席卷下,医疗行业正经历着深刻变革,大型医院作为医疗服务的核心枢纽,积累了海量的数据,涵盖患者的基本信息、诊断记录、检验报告、影像资料等多个维度。这些数据不仅规模庞大,而且增长速度迅猛,传统的中央处理器(C…

C#新语法

目录 顶级语句&#xff08;C#9.0&#xff09; using 全局using指令&#xff08;C#10.0&#xff09; using资源管理问题 using声明&#xff08;C#8.0&#xff09; using声明陷阱 错误写法 正确写法 文件范围的命名空间声明&#xff08;C#10.0&#xff09; 可空引用类型…

WPF基础 | WPF 布局系统深度剖析:从 Grid 到 StackPanel

WPF基础 | WPF 布局系统深度剖析&#xff1a;从 Grid 到 StackPanel 一、前言二、Grid 布局&#xff1a;万能的布局王者2.1 Grid 布局基础&#xff1a;构建网格世界2.2 子元素定位与跨行列&#xff1a;布局的精细操控2.3 自适应布局&#xff1a;灵活应变的秘诀 三、StackPanel…

基于微信小程序的网上订餐管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

网盘资源查找工具---AI功能

01 软件介绍 这是一款融入了ai技术的网盘搜索神器&#xff0c;可以让你更快&#xff0c;更精准的找到自己需要的文件&#xff0c;不管你是找影视&#xff0c;音乐&#xff0c;还是找软件或者学习资料都可以&#xff0c;欢迎前来使用。 02 功能展示 该软件非常简洁&#xff…

JAVA:利用 Content Negotiation 实现多样式响应格式的技术指南

1、简述 Content Negotiation&#xff08;内容协商&#xff09; 是 RESTful 服务的重要特性&#xff0c;允许客户端和服务器根据请求的不同特性动态选择适合的响应格式。它是一种在 HTTP 协议中实现的机制&#xff0c;通过它&#xff0c;服务器能够根据客户端需求返回适合的内…

Hook 函数

什么是hook函数&#xff1f; 在计算机编程中&#xff0c;hook函数是指在特定的事件发生时被调用的函数&#xff0c;用于在事件发生前或后进行一些特定的操作。通常&#xff0c;hook函数作为回调函数被注册到事件处理器中&#xff0c;当事件发生时&#xff0c;事件处理器会自动…

飞牛NAS新增虚拟机功能,如果使用虚拟机网卡直通安装ikuai软路由(如何解决OVS网桥绑定失败以及打开ovs后无法访问飞牛nas等问题)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 飞牛NAS虚拟机安装爱快教程 📒🛠️ 前期准备🌐 网络要求💾 下载爱快镜像🚀 开始安装💻 开启IOMMU直通🌐 配置网络🚨 解决OVS网桥绑定失败以及打开ovs后无法访问飞牛nas等问题➕ 创建虚拟机🎯 安装ikuai💻 进…

js手撕 | 使用css画一个三角形 使用js修改元素样式 驼峰格式与“-”格式相互转化

1.使用css画一个三角形 借助 border 实现&#xff0c;在 width 和 height 都为 0 时&#xff0c;设置 border&#xff0c;便会呈现三角形。想要哪个方向的三角形&#xff0c;设置其他三边为 透明即可。同时&#xff0c;可以通过调整不同边的宽度&#xff0c;来调整三角形的高度…

IoTDB 2025 春节值班与祝福

2025 春节快乐 瑞蛇迎吉庆&#xff0c;祥光映华年&#xff0c;2025 春节已近在眼前。社区祝福 IoTDB 的所有关注者、支持者、使用者 2025 新年快乐&#xff0c;“蛇”来运转&#xff01; IoTDB 团队的春节放假时间为 2025 年 1 月 27 日至 2 月 4 日&#xff0c;1 月 25 日、26…

React和Vue有什么区别,如何选择?

React和Vue有什么区别&#xff0c;如何选择&#xff1f; React 和 Vue 是当前最受欢迎的前端框架之一&#xff0c;两者在开发者中都有极高的声誉。它们都旨在帮助开发人员构建用户界面&#xff0c;但在实现方式和适用场景上有所不同。如果你正考虑在项目中选择 React 或 Vue&a…

poi在word中打开本地文件

poi版本 5.2.0 方法1&#xff1a;使用XWPFFieldRun&#xff08;推荐&#xff09; 比如打开当前相对路径的aaaaa.docx XWPFFieldRun run paragraph.createFieldRun();CTRPr ctrPr run.getCTR().addNewRPr();CTFonts font ctrPr.addNewRFonts();// 设置字体font.setAscii(&quo…

15_业务系统基类

创建脚本 SystemRoot.cs 因为 业务系统基类的子类 会涉及资源加载服务层ResSvc.cs 和 音乐播放服务层AudioSvc.cs 所以在业务系统基类 提取引用资源加载服务层ResSvc.cs 和 音乐播放服务层AudioSvc.cs 并调用单例初始化 using UnityEngine; // 功能 : 业务系统基类 public c…

Linux 权限管理

hello&#xff01;这里是敲代码的小董&#xff0c;很荣幸您阅读此文&#xff0c;本文只是自己在学习Linux过程中的笔记&#xff0c;如有不足&#xff0c;期待您的评论指点和关注&#xff0c;欢迎欢迎~~ ✨✨个人主页&#xff1a;敲代码的小董 &#x1f497;&#x1f497;系列专…

可以称之为“yyds”的物联网开源框架有哪几个?

有了物联网的发展&#xff0c;我们的生活似乎也变得更加“鲜活”、有趣、便捷&#xff0c;包具有科技感的。在物联网&#xff08;IoT&#xff09;领域中&#xff0c;也有许多优秀的开源框架支持设备连接、数据处理、云服务等&#xff0c;成为被用户们广泛认可的存在。以下给大家…

【25美赛A题-F题全题目解析】2025年美国大学生数学建模竞赛(MCM/ICM)解题思路|完整代码论文集合

我是Tina表姐&#xff0c;毕业于中国人民大学&#xff0c;对数学建模的热爱让我在这一领域深耕多年。我的建模思路已经帮助了百余位学习者和参赛者在数学建模的道路上取得了显著的进步和成就。现在&#xff0c;我将这份宝贵的经验和知识凝练成一份全面的解题思路与代码论文集合…

MySQL数据库基础

1、什么是数据库 存储数据用文件就可以了&#xff0c;为什么还要弄个数据库? 文件保存数据有以下几个缺点&#xff1a; 文件的安全性问题文件不利于数据查询和管理文件不利于存储海量数据文件在程序中控制不方便 数据库存储介质&#xff1a; 磁盘内存 为了解决上述问题&a…