当前位置: 首页 > news >正文

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

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;
}

相关文章:

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

Linux文件系统 inode 节点 &#xff08;index node&#xff09;&#xff1a;给每个文件赋予一个称为 i 节点的数据结构。 inode 一开始是存储在硬盘中的&#xff0c;只有当文件被打开的时候&#xff0c;其对应的 i 节点才加载到内存中。 总结&#xff1a; Linux 中&#xff0c…...

【操作系统】聊聊Linux软中断

什么是中断 中断是系统用来响应硬件设备请求的一种机制&#xff0c;会打断进程的正常调度和执行&#xff0c;转而去执行内核中的中断处理程序。 比如你正在看书&#xff0c;你女朋友叫你出去逛街。你就需要先放下手里的事情&#xff0c;然后逛街。回来之后&#xff0c;在接着看…...

公众号迁移个人可以迁移吗?

公众号账号迁移的作用是什么&#xff1f;只能变更主体吗&#xff1f;很多小伙伴想做公众号迁移&#xff0c;但是不知道公众号迁移有什么作用&#xff0c;今天跟大家具体讲解一下。首先公众号迁移最主要的就是修改公众号的主体了&#xff0c;比如我们公众号原来是A公司的&#x…...

全国职业技能大赛云计算--高职组赛题卷⑤(容器云)

全国职业技能大赛云计算--高职组赛题卷⑤&#xff08;容器云&#xff09; 第二场次题目&#xff1a;容器云平台部署与运维任务2 基于容器的web应用系统部署任务&#xff08;15分&#xff09;任务3 基于容器的持续集成部署任务&#xff08;15分&#xff09;任务4 Kubernetes容器…...

支撑位和阻力位在Renko和烛台图如何使用?FPmarkets澳福3秒回答

很多投资者都知道&#xff0c;Renko图表和普通日本烛台都会采用相同的交易信号&#xff0c;即支撑位和阻力位。那么支撑位和阻力位在Renko和烛台图如何使用?FPmarkets澳福3秒回答。 这些信号在任何时间框架上都会出现&#xff0c;且在蜡烛图交易中颇受欢迎。对于Renko图表而言…...

如何在32位MCU用printf()函数打印64位数据

1. 在32位MCU上定义64位变量&#xff1a; unsigned long long time_base; unsigned long long temp_time;2. 调用打印函数&#xff1a; printf("RFID:time_base:%d\r\n",time_base); printf("RFID:temp_time:%d\r\n",temp_time); printf("RFID:Ru…...

Python爬虫程序设置代理常见错误代码及解决方法

Python爬虫程序设置代理是爬虫程序中常用的技巧&#xff0c;可以有效地绕过IP限制&#xff0c;提高爬虫程序的稳定性和效率。然而&#xff0c;在设置代理时&#xff0c;常会出现各种错误代码&#xff0c;这些错误代码可能会影响程序的正常运行&#xff0c;甚至导致程序崩溃。本…...

3D点云目标检测:Centerformer训练waymo数据集

一、环境准备 项目地址:centerformer 1.0、基础环境 python 3.8.0 torch 1.9.1cu111 waymo-open-dataset-tf-2-6-0 1.4.9 spconv 1.2.1 其余按照requirement.txt里安装就行 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt由于我本人是在…...

火山引擎DataLeap推出两款大模型应用: 对话式检索与开发 打破代码语言屏障

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 自上世50年代&#xff0c;以“计算机”作为代表性象征的信息革命开始&#xff0c;社会对于先进生产力的认知便开始逐步更迭——从信息化&#xff08;通常认为是把企…...

windows上配置vscode C/C++代码跳转

windows上配置vscode C/C代码跳转 安装插件 C/C 官方的 C/C 插件&#xff0c;必备的插件&#xff0c;是代码跳转、自动补全、代码大纲显示等功能的基础。 Gtags C/C GNU Global GNU Global除了安装该插件之外&#xff0c;还需要在本地下载安装GNU Global工具。多看下插件…...

【Xilinx】基于MPSoC的OpenAMP实现(一)

【Xilinx】基于MPSoC的OpenAMP实现&#xff08;一&#xff09; 一、开发环境1、开发思路2、下载官方bsp包 二、编译Linux1、配置petalinux环境变量2、创建工程3、进入目录4、设置缓存目录&#xff08;重点&#xff1a;可离线编译&#xff0c;加快编译速度&#xff09;5、配置u-…...

代码随想录算法训练营总结篇|完结撒花

完结撒花&#xff0c;真不敢相信60天坚持下来了。 算法一直是我的超级超级弱项&#xff0c;属于小白中的小白。一开始是想自己刷的&#xff0c;打开leetcode第一题&#xff0c;吼哟好家伙&#xff0c;梦开始的地方直接破碎。之前刷B站的时候就有学习up推荐算法可以看看代码随想…...

uniapp、vue实现滑动拼图验证码

uniapp、vue实现滑动拼图验证码 实际开发工作中&#xff0c;在登陆的时候需要短信验证码&#xff0c;但容易引起爬虫行为&#xff0c;需要用到反爬虫验证码&#xff0c;今天介绍一下拼图验证码&#xff0c;解决验证码反爬虫中的滑动验证码反爬虫。滑动拼图验证码是在滑块验证码…...

【ArcGIS】土地利用变化分析详解(矢量篇)

土地利用变化分析详解-矢量篇 土地利用类型分类1 统计不同土地利用类型的面积/占比1.1 操作步骤Step1&#xff1a;Step2&#xff1a;计算面积Step3&#xff1a;计算占比 2 统计不同区域各类土地利用类型的面积2.1 操作步骤 3 土地利用变化转移矩阵3.1 研究思路3.2 操作步骤 4 分…...

VS2022创建控制台应用程序后没有Main了,如何显示Main?

文章目录 问题描述原因解决方案简单的顶级语句试用计算器 其他文章 问题描述 用VS2022创建一个控制台应用后&#xff0c;没有名称空间和Main函数了&#xff0c;只有一个WriteLine&#xff0c;如下所示。 // See https://aka.ms/new-console-template for more information Co…...

当当网商品详情数据接口

当当网商品详情数据接口可以通过当当网的开放平台获取相关信息。您可以注册当当开放平台账号&#xff0c;并按照要求提交申请获取API接口的调用凭证。获得授权后&#xff0c;您将会收到一组AccessKey和SecretKey。使用编程语言&#xff08;如Java&#xff09;调用API接口&#…...

ultraEdit正则匹配多行(xml用)

在ultraEdit中&#xff0c;我想选取<channel到</channel>之间的多行&#xff08;进行删除&#xff09;。在perl模式下&#xff0c;命令为“<channel[\s\S]?</channel>”。下面是xml文件&#xff1a; <!--This XML file does not appear to have any sty…...

Mac上的utools无法找到本地搜索插件

utools安装地址 utools本地搜索用法 目前本地搜索只在win下&#xff0c;mac无福了 Mac可用cmdspace方法使用聚焦搜索&#xff0c;来搜索本地文件...

win11 administrator 账户运行不提示授权

...

docker部署nginx下日志自动切割方法

前言&#xff1a;nginx采用docker部署&#xff0c;简单方便&#xff0c;但出现一个问题&#xff0c;就是日志没有自动切割&#xff0c;导致access.log 无限增大。如果非docker安装&#xff0c;则nginx的日志默认有切割的&#xff0c;那docker为何没有呢&#xff0c;最后发现&am…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...