【操作系统笔记十一】进程间通信

Linux文件系统

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

inode 节点 (index node):给每个文件赋予一个称为 i 节点的数据结构。

inode 一开始是存储在硬盘中的,只有当文件被打开的时候,其对应的 i 节点才加载到内存中。

在这里插入图片描述

总结:

  • Linux 中,用户态通过读写文件的 Api 进行系统调用,在内核态中,上层是虚拟文件操作系统 VFS,它为用户态提供统一接口,屏蔽底层实现细节,VFS 层定义了底层具体的文件系统需要实现的接口,VFS 层往下对接不同的具体的文件系统如 ext4,具体的文件系统再去操作磁盘的文件块信息

  • Linux 中每个文件对应一个称为 iNode 的数据结构,inode中包含了文件的元数据以及若干的块地址信息,inode一开始存储在磁盘中,当文件被打开时,inode节点会被加载到内存当中

  • 每个进程的task_struct中包含files_struct结构体,files_struct中又包含一个fd数组fd_arrayfd_array中则包含对应文件的文件操作符filefile文件操作符是通过inode去读写文件的,inode中定义了inode_options,而具体的底层文件系统则实现了inode_options中定义的对应读写接口的具体方法

管道

在这里插入图片描述

Linux 进程间通信方式:管道、共享内存、信号量、消息队列

① 匿名管道

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

② 命名管道

在这里插入图片描述

管道的实现

一个文件可以同时被多个进程访问

在这里插入图片描述

所以,我们可以使用文件来实现进程间的通信,管道就是基于文件系统来实现的。

实现进程和其子进程之间的管道通信

在这里插入图片描述

父进程在复制子进程时,会把父进程的相关信息全部拷贝过来,其中就包括file_struct结构体,而这个结构体中就包含了文件读写inode的两个文件描述符,一个 file_0 只读, 一个 file_1 只写,由于是复制的,所以父子进程的这俩文件描述符是指向的同一个文件的inode

在这里插入图片描述

此时把父进程的 file_0 只读文件描述符 close 掉,把子进程的 file_1 只写文件描述符 close 掉,父进程只保留只写文件描述符,子进程只保留只读文件描述符,这样父进程就可以和子进程通信了(父进程只写,子进程只读,半双工)。

匿名管道的实现

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

匿名管道底层实现:

在这里插入图片描述

匿名管道通过虚拟文件系统 VFS 调用底层的 pipefs 内存文件系统,也就是说底层实现是基于 pipefs 文件系统的。

pipefs 文件系统的数据结构:https://www.processon.com/view/link/62822757e401fd36f6bcc5dd

管道在内存中的实现本质就是一段内核 buffer 内存,不同的文件操作符(一个读一个写)对这段 buffer 进行读写操作。

关于 ps -ef | grep systemd 命令背后的匿名管道的底层实现数据结构:

在这里插入图片描述

命名管道底层实现流程图:

在这里插入图片描述

总结

  • 管道是基于文件系统来实现的,也就是多个进程对同一个文件进行读写来实现进程间通信

  • 进程和子进程之间的管道通信:父进程在fork子进程时,会把父进程相关信息全部拷贝过来,其中包括file_struct结构体,file_struct中包含了文件读写inode的两个文件描述符,一个file_0只读,一个file_1只写,由于是复制的,所以父子文件的这俩文件描述符是指向同一个文件的inode, 此时把父进程的file_0只读 fd 关闭掉,然后再把子进程的file_1只写 fd 关闭掉,父进程只保留只写 fd ,子进程只保留只读 fd ,这样父进程就可以和子进程进行通信了(父进程写,子进程读)。

  • 匿名管道的虚拟文件系统 VFS 对应的底层文件系统实现是基于 pipefs 内存文件系统

  • 管道在内存中的实现本质就是一段内核 buffer 内存,不同的文件操作符(一个读一个写)对这段 buffer 进行读写操作。

  • 用户态:read/write → 内核态 VFS:task_structfiles_structfd_arrayfds[0] fds[1]file0 file1file_optsinodepipe_inode_infopipe_bufs

共享内存 (shared memory)

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

创建共享内存

shmget - allocates a System V shared memory segment

#include <sys/ipc.h>
#include <sys/shm.h> 
// 返回根据 key 生成的 shmid
int shmget(key_t key, size_t size, int shmflg); 

参数含义:

  • key:唯一标识新创建的共享内存

  • size:共享内存的大小,向上取整成PAGE_SIZE的倍数

  • shmflg:一些标志信息

    IPC_CREAT:根据 key 判断对应的共享内存段是否存在,如果不存在,则创建;如果存在,则返回已经存在的共享内存段

    IPC_EXCL: 和 IPC_CREAT 一起用,如果已经存在 key 对应的共享内存 则失败

    读写权限信息

映射共享内存

  • shmat映射共享内存到进程的虚拟地址空间,返回映射的虚拟内存段的起始地址
  • shmdt解除映射,如果成功返回 0,否则返回 -1
#include <sys/types.h>
#include <sys/shm.h>void *shmat(int shmid, const void *shmaddr, int shmflg); 
int shmdt(const void *shmaddr); 

参数含义:

  • shmid:共享内存的唯一标识 id,即填入由 shmget 函数返回的值
  • shaddr: 内存映射起始地址,如果是NULL的话,内核会分配
  • shaflg:是一组标志位,通常为0

注意:创建和映射共享内存操作只是在内核中维护一些数据结构,并没有真的分配物理内存。真正分配物理内存是在访问这块虚拟内存地址中的数据发生缺页异常时,由缺页异常处理程序维护进程页表中的虚拟页号和物理页号的映射关系的。

在这里插入图片描述

这里进程 A 和进程 B 访问的是同一块物理内存上的相同的物理页。

参考代码:

在这里插入图片描述

在这里插入图片描述

共享内存的底层原理是基于 tmpfs 文件系统:https://www.processon.com/view/link/6277c3921e085327716f5971

总结

  • 共享内存的原理:不同进程的虚拟内存地址会映射到相同的物理内存上,这样两个进程通过访问同一块物理内存,达到通信的目的。(一般情况下,不同进程的虚拟地址是映射到不同物理地址的)

  • 在创建共享内存时并没有真的分配物理内存,真的分配是进程在读、写数据的时候,发生缺页异常,由缺页异常处理程序分配共享内存(物理内存)的页号到进程的虚拟页表中

  • 共享内存的底层原理是基于 tmpfs 文件系统, Linux中一切皆文件

问题:mmap 内存映射和 shm 共享内存有什么区别?

  • Linux 中的内存映射是指将一块虚拟地址内存空间和一个文件对象关联起来,以初始化这块虚拟内存的内容,文件对象可以是一个普通磁盘文件,也可以是一个匿名文件(一块只包含二进制零的物理内存)
  • mmap 内存映射时,被映射的对象可以是一个磁盘文件,也可以是一个请求二进制零的匿名对象。如果是前者,在发生缺页异常时,缺页异常处理程序除了需要维护页表外,还需要将磁盘文件内容加载到物理内存中;如果是后者,则就相当于将一块物理内存和虚拟内存进行映射。
  • shm 共享内存映射是直接每个进程将虚拟内存映射到同一块物理内存,不涉及到磁盘文件。shm 保存在物理内存,这样读写的速度要比磁盘要快,但是存储量不是特别大。
  • 所以可以简单的认为 mmap 主要是用于映射磁盘文件的,而 shm 是直接用于映射物理内存的
  • mmap 有一个好处是,把文件保存在磁盘上,当设备机器重启时,这个文件还保存了操作系统同步的映像,所以 mmap 不会丢失,但是 shm 就会丢失。

信号量

在一个进程内,多个线程同时更新共享资源,有数据并发安全问题,解决方案有:

  • ① 原子操作
  • ② 锁机制 - 管程
  • ③ 信号量

多个进程同时更新共享内存(共享资源),也有数据安全问题,解决方案:信号量

IPC 的信号量 (semaphore)

原理思想和并发编程中的信号量是一样的,但是两者的实现完全不同:

  • IPC 的信号量实现很复杂,是在内核态中实现的,而并发编程中的信号量是在用户态实现,基于原子操作实现

  • IPC 的信号量是操作系统层面用于解决多个进程之间的共享内存并发读写问题,并发编程中的信号量用于解决同一个进程的多个线程之间的共享资源读写问题

一个是在内核态实现的,一个是应用程序代码中实现的。

在这里插入图片描述

参考代码:

在这里插入图片描述

消息队列

创建消息队列msgget - get a System V message queue identifier

#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/msg.h>int msgget(key_t key, int msgflg); // 函数返回返回新创建的消息队列的 id

参数含义:

  • key:唯一标识新创建的消息队列

  • msgflg:一些标志信息

    IPC_CREAT:根据 key 判断对应的共享内存段是否存在,如果不存在,则创建;如果存在,则返回已经存在的共享内存段

    IPC_EXCL:和 IPC_CREAT 一起用,如果已经存在 key 对应的共享内存,则失败

    读写权限信息

发送和接收消息msgsnd, msgrcv - System V message queue operations

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); // 返回值:成功返回0;失败返回-1
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtype, int msgflg); // 成功返回接收个数,失败,返回-1
  • msqid: 由msgget函数返回的消息队列的标识符
  • msgp: 消息缓冲区指针,指针指向准备发送/接收的消息
  • msgflg: 为0表示阻塞方式,设置IPC_NOWAIT表示非阻塞方式异步接发消息
  • msgsz: 是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型
  • msgtype:
    等于0,那么读取消息队列中的第一条消息
    大于0,那么读取消息队列中的第 msgtype 条消息(这里是读取类型等于msgtype的第一条消)
    小于0,那么读取小于等于msgtype绝对值最小的 msgtype 的消息

参考代码:

int main() {int mq_id = get_mq_id(); struct msg_buffer buffer;printf("enter message type: "); scanf("%d", &buffer.mtype);printf("enter message contenit:");scanf("%s", &buffer.mtext);int len = strlen(buffer.mtext) + 1;if (msgsnd(mq_id, &buffer, len, IPC_NOWAIT) == -1) { perror("fail to send message.");exit(1); }return 0; 
}
#include <string.h>
#include "mq.h" int main() {int mq_id = get_mq_id(); struct msg_buffer buffer; int type;scanf("%d", &type);if (msgrcv(mq_id, &buffer, 1024, type, IPC_NOWAIT) == -1) { perror("fail to recv message.");exit(1); }printf("received message type : %d, text: %s, \n", buffer.mtype, buffer.mtext); return 0;
}

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

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

相关文章

CHAPTER 11: DESIGN A NEWS FEED SYSTEM

Step 1 - Understand the problem and establish design scope Candidate: Is this a mobile app? Or a web app? Or both? Interviewer: Both Candidate: What are the important features? Interview: A user can publish a post and see her friends’ posts on the ne…

JAVA 二叉树超详解(1)

树形结构 概念 树是一种非线性的数据结构&#xff0c;它是由n(n>0)个有限结点组成的一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它根朝上&#xff0c;而叶朝下的&#xff0c;具有以下的特点&#xff1a; 1.有一个特殊的结点&…

云原生Kubernetes:K8S集群list-watch机制与 pod调度约束

目录 一、理论 1.K8S的list-watch 机制 2.亲和性 二、实验 1. 指定调度节点 2.节点亲和性 3.亲和性和反亲和 三、问题 1.新生成pod一直为pending 2.如何一次性删除pod和deployment 3.pod亲和性资源报错 4.pod反亲和性资源报错 四、总结 一、理论 1.K8S的list-wat…

【操作系统】24王道考研笔记——第五章 IO管理

第五章 IO管理 一、IO设备 1.1 基本概念与分类 1.2 IO控制器 电子部件 IO控制器组成 值得注意的小细节&#xff1a;①一个I/O控制器可能会对应多个设备&#xff1b; ②数据寄存器、控制寄存器、状态寄存器可能有多个&#xff08;如&#xff1a;每个控制/状态寄存器对应一个…

Java流式编程的使用

流式编程的使用步骤 使用流式编程的步骤就是: 设置数据源, 设置数据处理的方式,设置收集结果的方式。 使用filter方法实现过滤条件 例子为下&#xff08;查询年龄大于18的用户&#xff09;: Testpublic void streamTest1() {List<Student> students Arrays.asList(ne…

在gazebo仿真环境中加载多个机器人

文章目录 前言一、基本概念1、xacro2、Gazebo 加载单个机器人模型 二、原先launch文件代码三、 修改launch文件加载多个机器人总结 前言 单个机器人的各项仿真实验都基本完成&#xff0c;也实现了远程控制&#xff0c;接下来主要对多机器人编队进行仿真实验&#xff0c;在进行…

【EI会议征稿】第三届计算机图形学、人工智能与数据处理国际学术会议 (ICCAID 2023)

第三届计算机图形学、人工智能与数据处理国际学术会议 2023 3rd International Conference on Computer Graphics, Artificial Intelligence and Data Processing (ICCAID 2023) 第三届计算机图形学、人工智能与数据处理国际学术会议&#xff08;ICCAID 2023&#xff09;将于…

14.抽象工厂模式

UML 代码 #include <iostream> #include <list> using namespace std;class AbstractProductA { public:virtual void showa() 0; }; class ProductA1:public AbstractProductA { public:virtual void showa(){cout << "我是A1" << endl;}…

短视频矩阵系统源代码开发搭建分享--代码开源SaaS

一、什么是短视频矩阵系统&#xff1f; 短视频矩阵系统是专门为企业号商家、普通号商家提供帐号运营从流量 到转化成交的一站式服务方案&#xff0c;具体包含&#xff1a;点赞关注评论主动私信 &#xff0c;评论区回复&#xff0c;自动潜客户挖掘&#xff0c;矩阵号营销&#x…

工具及方法 - 二进制编辑软件

之前介绍过用Notepad和VSCode进行二进制文件编辑。 很多通用型的文本编辑器都会集成二进制文件编辑功能&#xff0c;或者使用插件等形式扩展此项功能。比如vi/vim等工具。 而且&#xff0c;作为文本编辑、二进制文件编辑一类的工具&#xff0c;数量众多&#xff0c;各有特色。…

机器学习 day36(纯度)

熵 这些例子的纯度和熵如图所示&#xff0c;且左侧为熵函数图熵函数是判断某组数据是否纯度高的指标 熵函数公式如上图&#xff0c;底数为2仅为了使函数峰值为1&#xff0c;且设定0log(0)为0&#xff0c;但log(0)为无穷大

Swift SwiftUI 隐藏键盘

如果仅支持 iOS 15 及更高版本&#xff0c;则可以通过聚焦和取消聚焦来激活和关闭文本字段的键盘。 在最简单的形式中&#xff0c;这是使用 FocusState 属性包装器和 focusable() 修饰符完成的-第一个存储一个布尔值&#xff0c;用于跟踪第二个当前是否被聚焦。 Code struct C…

Python中统计单词出现的次数,包含(PySpark方法)

思路&#xff1a; 定义一个函数&#xff0c;使用open函数&#xff0c;将文本内容打开。 定义一个空字典和空列表&#xff0c;进行循环及条件判断操作def count_word(file_path):dict_data {} #定义一个空字典f open(file_path,"r",encoding"UTF-8")lis…

cadence - 在allegro中出报告(Padstack Usage Report)来辅助制作orcad原理图封装

文章目录 cadence - 在allegro中出报告(Padstack Usage Report)来辅助制作orcad原理图封装概述笔记做PCB封装出报告 - Padstack Usage Report做原理图封装END cadence - 在allegro中出报告(Padstack Usage Report)来辅助制作orcad原理图封装 概述 现在做封装, 还是手工弄. 在…

Hadoop-sqoop

sqoop 1. Sqoop简介及原理 简介&#xff1a; Sqoop是一款开源的工具,主要用于在Hadoop(Hive)与传统的数据库(mysq1.postgresql..)间进行数据的传递&#xff0c;可以将一个关系型数据库&#xff08;例如: MySQL ,Oracle ,Postgres等&#xff09;中的数据导进到Hadoop 的HDFS中&…

Java 函数式编程思考 —— 授人以渔

引言 最近在使用函数式编程时&#xff0c;突然有了一点心得体会&#xff0c;简单说&#xff0c;用好了函数式编程&#xff0c;可以极大的实现方法调用的解耦&#xff0c;业务逻辑高度内聚&#xff0c;同时减少不必要的分支语句&#xff08;if-else&#xff09;。 一、函数式编…

性能测试 —— Tomcat监控与调优:status页监控

Tomcat服务器是一个免费的开放源代码的Web 应用服务器&#xff0c;Tomcat是Apache 软件基金会(Apache Software Foundation)Jakarta 项目中的一个核心项目&#xff0c;由Apache、Sun 和其他一些公司及个人共同开发而成。 Tomcat是一个轻量级应用服务器&#xff0c;在中小型系统…

20230918使用ffmpeg将mka的音频转为AAC编码以便PR2023来识别

20230918使用ffmpeg将mka的音频转为AAC编码以便PR2023来识别 2023/9/18 20:58 ffmpeg -i 1.mka -acodec aac 1.mp4 ffmpeg -i 1.mka -vn -c:a aac 2.aac ffmpeg -i 1.mka -vn -c:a aac 2.MP4 ffmpeg mka 转 aacmp4 https://avmedia.0voice.com/?id42526 用ffmpeg将mka格式转化…

Mybatis学习笔记11 缓存相关

Mybatis学习笔记10 高级映射及延迟加载_biubiubiu0706的博客-CSDN博客 缓存:cache 缓存的作用:通过减少IO的方式,来提高程序的执行效率 Mybatis的缓存:将select语句的查询结果放到缓存(内存)当中,下一次还是这条select语句的话,直接从缓存中取,不再查数据库.一方面是减少了I…

【新版】系统架构设计师 - 案例分析 - 信息安全

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 案例分析 - 信息安全安全架构安全模型分类BLP模型Biba模型Chinese Wall模型 信息安全整体架构设计WPDRRC模型各模型安全防范功能 网络安全体系架构设计开放系统互联安全体系结构安全服务与安全机制…