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

进程本地通信

目录

本地通信的本质

匿名管道

基本原理

相关系统调用

匿名管道特点

与shell关联起来

进程池的应用

命名管道

SystemV IPC-共享内存

共享内存特点

SystemV IPC-消息队列

消息队列特点

SystemV IPC-信号量

信号量特点

SystemV IPC之间的联系

shell查询IPC的命令


本地通信的本质

同一台主机,同一个OS,不同进程之间的通信,本质是让不同的进程看到同一份资源


匿名管道

基本原理

在父进程中分别以读和写两种方式打开同一份文件。子进程继承打开的文件后,关闭父进程以读方式打开的文件,关闭子进程以写方式打开的文件,这样父进程只能写,子进程只能读,实现单向通信。如果不关闭不需要的fd不会报错,但是一来会导致读写混乱,二来会浪费fd。

匿名管道的通信原理大致就是这样子,但是这里要澄清两点:

  1. 使用系统提供给我们的pipe调用来实现这种通信机制的话,文件相关的内核级文件缓冲区不会也没必要和磁盘交互,因为没有涉及到具体的文件,只是利用了OS文件管理的一部分机制来实现父子进程看到同一份资源。也是因此我们打开的文件没有名字,所以叫匿名管道(当然如果你用手搓的方式实现的话那就另说了)。
  2. 一般是以读和写方式分别打开文件一次(有两个struct_file),而不是以读写方式只打开一次文件(只有一个struct_file)。

相关系统调用

用系统调用pipe打开的管道文件的内核级缓冲区不和磁盘有联系,是纯内存级的缓冲区

匿名管道特点

与shell关联起来

当我们执行类似与这样的命令:ps -ajx | grep a | grep ab,shell会做如下处理:

  1. 分析字符串“ps -ajx | grep a | grep ab”,发现有两个 “|”,因此创建两个管道
  2. 然后依次创建三个子进程,第一个子进程的输出重定向为管道1,并执行ps -ajx命令;第二个子进程的输入重定向为管道1,输出重定向为管道2,并执行grep a 命令;第三个子进程的输入重定向为管道2,输出仍旧是显示器文件不变

grep内部首先是read函数,这样就可以预见,我们执行了一串命令,并把输出结果依次传递给后面的命令,再由做后一个命令输出到显示器,这样就实现了类似于过滤输出的效果,这就是shell中使用“|”的本质,下面是一个demo代码:

// 伪代码 function execute_pipeline(commands[]): int pipe_count = len(commands) - 1 int pipes[pipe_count][2] // 每个管道有两个文件描述符 // 1. 创建所有管道 for i = 0 to pipe_count-1: pipe(pipes[i]) // 2. 创建并执行每个命令 for i = 0 to len(commands)-1: pid = fork() if pid == 0: // 子进程 // 设置输入(除了第一个命令) if i > 0: dup2(pipes[i-1][0], STDIN_FILENO) // 从前一个管道读 // 设置输出(除了最后一个命令) if i < len(commands)-1: dup2(pipes[i][1], STDOUT_FILENO) // 向后一个管道写 // 关闭所有管道描述符(子进程不需要) for j = 0 to pipe_count-1: close(pipes[j][0]) close(pipes[j][1]) // 执行命令 exec(commands[i]) exit(1) // exec 失败 else: // 父进程 // 继续创建下一个子进程 // 3. 父进程关闭所有管道描述符 for i = 0 to pipe_count-1: close(pipes[i][0]) close(pipes[i][1]) // 4. 等待所有子进程结束 for i = 0 to len(commands)-1: wait()

进程池的应用

创建多个子进程的同时为父进程与每个子进程建立一个管道,并用例如vector数据结构管理所有的管道。每个子进程都在read函数阻塞,等待命令。


命名管道

用系统接口 mkfifo 函数创建一个特殊的管道文件,他是真实存在的文件,唯一不同于其他文件的是,它的文件类型是P,并且OS规定只要是P类型的文件,其内核缓冲区不会与磁盘进行交互。如此,可以在不同的进程中用正常方式打开这个文件并读写,实现通信

命名管道特点:

  • 可以用于在无血缘关系的进程间进行通信
  • 以及匿名管道的
  • 所有特点

SystemV IPC-共享内存

由进程发起请求,再由操作系统开创一块内存空间,要通信的进程把这块内存空间挂接到自己的虚拟地址的共享空间上,这样通信双方共享一块内存,一但一个进程对内存写入数据,另一个进程就可获知

共享内存可能会有很多,进程要通信就要根据标识符找到对应的共享内存,因此每个共享内存都有一个管理它的结构体,里面包含了这块共享内存的标识符等信息,OS也把所有的共享内存结构体组织起来统一管理(先描述,再组织)。

共享内存的标识符是由用户指定的,因为如果由操作系统分配,那么只有创建共享内存的进程可以拿到标识符,而其他想要使用共享内存的进程是拿不到这个标识符的。不过系统也提供了一个接口给我们生成一个标识符:

下面介绍创建/获取共享内存的函数:

创建共享内存时候还需要把它挂载到进程的共享区(两个进程都挂载上,它们就可以互相通信了):

共享内存在语义上不属于某个进程,因此进程退出他也不会销毁,我们需要主动对其进行销毁:

也可以通过shell命令对共享内存进行销毁

共享内存特点

  • 通信最速度快(不调用系统调用,并且拷贝次数比较少,因为我们可以直接往共享内存写入而不是先拷贝给用户再拷贝给内核)
  • 支持大块数据传递(而管道最大64KB)
  • 支持双向通信
  • 没有保护机制
  • 生命周期随内核(不是随进程!)

SystemV IPC-消息队列

内核创建一个队列,通信的双方通过在队列中添加节点和获取节点来实现通信。节点中有id属性,不同进程添加节点时设置为自己的id,这样可以区分数据是谁发出的。

消息队列特点

  • 生命周期随内核
  • 本质上是创建了一个队列以存放发送的结构体消息

SystemV IPC-信号量

信号量可以表示一种资源的数量,也可以用于进程间同步(类似于“互斥同步”一节中的POSIX信号量的用法),实际上,信号量是一种进行资源预定的计数器,他本身是共享资源,用于进程间通知,因此也算是一种本地通信方式

信号量特点

  • 生命周期随内核
  • 不以传送数据为目的,而是以通知或记录资源数目为目的
  • count为2就是二元信号量,可以充当一种简单的锁

SystemV IPC之间的联系

管理这三种通信的内核结构中都含有一个相同的结构体kern_ipc_perm,且他们都是各自内核结构的第一个元素,里面包含着他们共有的类型的信息(编号,权限,拥有者等)。

通过kern_ipc_perm,系统用一个柔性数组把所有类型所有数量的kern_ipc_perm管理在一个数组,如果要访问的是完整的IPC结构,只要把kern_ipc_perm类型转换成对应的内核指针类型即可,实现对System V IPC 通信的同一管理(多态)。其中柔性数组的下标就是用户拿到的shmid等id号。

这个柔性数组和它的大小(也就是申请通信的数量组成的结构体ipc_id_ary),本身被管理在ipc_ids中。而系统中有三个ipc_ids,管理的是同一个柔性数组:

这样访问通信的时候只要进入对应的ipc_ids就天然的知道自己要访问的是哪种通信。

  • 由于所有IPC都被统一管理,key和id当然也是统一的,也就是说,不同的通信也可能发生id或者key冲突。
  • 事实上,共享内存就是文件缓冲区!只不过把文件缓冲区映映射到了虚拟地址空间上,因此可以通过地址直接访问!
  • 匿名管道没有映射只能通过系统调用访问,而共享内存直接在用户态中用指针访问!

shell查询IPC的命令

http://www.jsqmd.com/news/624916/

相关文章:

  • MySQL Explain 计划优化实战案例
  • 华为MetaERP核算架构中管理单元的设计逻辑与实现原理,并与Oracle EBS的业务实体(OU)进行对比分析
  • 若依框架菜单扩展全攻略:从数据库到前端路由的完整流程解析
  • Agent Client Protocol 全景解析讨
  • BitTorrent Tracker列表技术深度解析与架构设计原理
  • 从公众号到后台:一次意外的教育系统未授权访问漏洞发现之旅
  • 从零到一:手把手教你用Labelme打造专属Mask数据集
  • 别再傻傻全量微调了!用Prompt-Tuning冻结大模型,成本直降99%
  • AI Agent 跑完任务怎么通知你?我写了个微信推送服务八
  • 梅德生物技术快报|重组蛋白纯化工程化实现:Amuc_0119 蛋白 Ni‑NTA 亲和层析全参数方案
  • AI原生体验设计为何92%失败?:从LLM幻觉到用户信任断层的5层认知陷阱与修复路径
  • 2、高数----数列极限(知识总结)
  • CentOS7物理机网卡驱动缺失?手把手教你搞定Intel i219-v网卡驱动安装
  • Cisco 18系列AP通过u-boot实现tftp镜像启动的详细步骤解析
  • [具身智能-349]:在MCP架构中,如何部署大模型、启动和初始大模型?MCP Client如何与大模型交互?
  • OSI七层模型实战指南:从物理层到应用层的网络排错技巧
  • 大模型工程化成本失控的5个信号,第3个90%团队至今未察觉:2026 Q1行业审计报告首发
  • 从网线到Wi-Fi:深入浅出聊聊曼彻斯特编码在以太网中的前世今生
  • 一物一码系统怎么搭建?从0到1的完整实施路径与避坑指南
  • STEP3-VL-10B效果展示:10B参数轻量模型,图片问答效果媲美百亿大模型
  • 嵌入式系统开发方法论
  • 从75Ω同轴线到100Ω差分线:一文搞懂不同传输线标准下的S参数转换与对比
  • Silk-v3-decoder技术架构解析:企业级音频格式转换解决方案
  • 3 小时免费完成 Cyber Security 项目并获得证书:快速入门与技能提升
  • Java垃圾回收算法与性能调优
  • 如何免费解锁Cursor Pro功能:3步实现AI代码编辑器无限使用终极指南
  • H20服务器多卡运行有错误gpu_partition ,tmux错误
  • 详解指针1
  • 现在不看就晚了:SITS2026圆桌紧急预警——2025Q3起,未建立AI原生ROI动态仪表盘的企业将丧失融资溢价权
  • 中小开发者AI工具选型:Pixel Fashion Atelier对比传统SD WebUI的像素工作流优势