Linux---进程间通讯
1 进程间通讯概述因为进程有着独立性的特点所以进程间的通讯不能像线程那样方便所以为了满足进程间通讯才有这些方法的诞生1-1 进程间通信目的1.数据传输一个进程需要将它的数据发送给另一个进程2 资源共享多个进程之间共享同样的资源。3 通知事件一个进程需要向另一个或一组进程发送消息通知它它们发生了某种事件如进程终止时要通知父进程。4 进程控制有些进程希望完全控制另一个进程的执行如Debug进程此时控制进程希望能够拦截另⼀个进程的所有陷⼊和异常并能够及时知道它的状态改1-2 进程间通信发展1管道2 System V进程间通信3 POSIX进程间通信(这里是轻量级进程间通讯即进程在线程的文章中会详细讲解)1-3 进程间通信分类管道1 匿名管道pipe2 命名管道System V IPC1 System V 消息队列2 System V 共享内存(详细谈)3 System V 信号量POSIX IPC1 消息队列2 共享内存3 信号量4 互斥量5 条件变量6 读写锁1-4 什么是进程间通讯进程间通讯(IPC inter-Process Communication)是运行在同一台计算机或不同计算机上的多个进程间进行数据交换和通讯的技术这是因为每个进程都有自己的地址空间它们无法直接访问彼此的数据因此需要通过特定的机制来实现通讯1-5 进程间怎么通讯进程通讯的本质是先让不同的进程看到同一份资源(内存)。然后才有通讯的条件。通讯的资源不是由任何一个进程提供的而是由OS设置同一的接口提供的通过系统调用接口来体现。从上述的概述中我相信各位已经对于进程间通讯有什么和有什么用有了一个初步的了解但是在Linux多年的发展依以来有很多的进程间的通讯方式已经被不再被频繁使用而且有一些其实是在线程部分使用会更多点(为什么进程间通讯和线程有关我们放到我们线程部分再解答)所以此文只介绍一些常见和重要有意义的通讯。2 管道什么是管道管道就是Unix中最古老的进程间通讯的方式我们把从一个进程链接到另一个进程的一个数据流称为一个“管道”3匿名管道3-1 系统调用接口#include unistd.h 功能: 创建⼀⽆名管道 原型 int pipe(int fd[2]); 参数: fd⽂件描述符数组,其中fd[0]表⽰读端, fd[1]表⽰写端 返回值: 成功返回0失败返回错误代码demo:#include iostream #include unistd.h using namespace std; int main() { int fd[2]; pipe(fd); int pid fork(); if (pid 0) { close(fd[1]); while (true) { sleep(1); int buf 0; read(fd[0], buf, sizeof(buf)); cout 子进程通过管道受到父进程的数据 buf endl; } } int cnt 1; while (true) { close(fd[0]); write(fd[1], cnt, sizeof(cnt)); cnt; } return 0; }3-2 用 fork 来共享管道原理3-3 站在文件描述符角度-深度理解管道其实从这个原理就可以看到父子之间通过看到同一个资源就是基于文件系统特殊实现的管道文件因为文件自带文件缓冲区所以父子进程同时看到这个文件缓冲区从而实现通讯由此可以看出匿名管道是复用了文件系统的那一套操作并且配上单独的系统调用来实现的3-4 站在内核角度度-管道本质但是匿名管道的inode是不会保存该管道的名字的那我们是怎么保证两个进程打开的是同一个管道文件呢子进程会继承父进程文件描述符表这也在一定程度上体现了匿名管道的特性所以看待管道就如同看待文件⼀样管道的使用和文件⼀致迎合了“Linux一切皆文件思想”。注意如果递归创建多个子进程那么在关闭管道的时候要fd的引用计数问题因为子进程是拷贝的父进程的地址空间所以递归创建的时候进程的w端不只是有父进程指向也有可能被其他子进程指向所以此时关闭的时候你需要倒着关或者保证子进程的w端只能指向父进程3-6 管道读写规则1当没有数据可读时1-1 O_NONBLOCK disableread调用阻塞即进程暂停执行一直等到有数据来到为止。1-2 O_NONBLOCK enableread调用返回-1errno值为EAGAIN。2当管道满的时候2-1O_NONBLOCK disable write调用阻塞直到有进程读走数据2-2O_NONBLOCK enable调⽤返回-1errno值为EAGAIN3如果所有管道写端对应的文件描述符被关闭则read返回0表示文件结尾4如果所有管道读端对应的文件描述符被关闭则write操作会产生信号SIGPIPE,进而可能导致write进程退出否则一直写却没有人读会让这个写操作没有意义操作系统不做没有意义的事5当要写入的数据量不大于PIPE_BUF时Linux将保证写入的原子性。6当要写入的数据量大于PIPE_BUF时Linux将不再保证写入的原子性。3-7 管道特点1 只能用于具有共同祖先的进程具有亲缘关系的进程之间进行通信。通常一个管道由一个进程创建然后该进程调用 fork此后父、子进程之间就可应用该管道。2 管道提供流式服务自带同步机制(按照一定的顺序进行访问)所以才导致了管道的第 3 和第 4 条的管道特性3 一般而言进程退出管道释放所以管道的生命周期随进程4 一般而言内核会对管道操作进行同步与互斥5 管道是半双工的数据只能向一个方向流动需要双方通信时需要建立起两个管道注意1 任何一个时刻一个发一个收 --- 半双工2 任何一个时刻可以同时发收 --- 全双工3-8 管道的 4 种情况1 写满读快 ---读端就要阻塞(进程)2 写快读慢 --- 满了的时候写端就要阻塞3 写关继续读 --- read读到返回值为0表示文件结尾4 读关闭写继续 --- 写端写入没有任何意义OS不会做没有意义的事情 ---OS会杀掉进程4 命名管道管道应用的一个限制就是只能在具有共同祖先具有亲缘关系的进程间通信。 如果我们想在不相关的进程之间交换数据可以使用FIFO文件来做这项工作它经常被称为命名管道。命名管道是一种特殊类型的文件4-1 创建一个命名管道4-1-1 系统命令$ mkfifo filename4-1-2 系统调用#include sys/types.h #include sys/stat.h int mkfifo(const char *filename,mode_t mode); 参数 filename:管道文件的路径和名称 mode:创建管道文件的初始权限注意一定要是8进制输入否则会错乱 返回值 0创建成功 -1创建失败demo 1:#include iostream #include unistd.h #include sys/types.h #include sys/stat.h using namespace std; int main() { mkfifo(./pipe,0x666); return 0; }注意mkfifo最后一个参数设置的是文件初始权限一定要是0开头的3位数字即8进制数据传入否则就会权限错乱传入0666传入666这个时候pipe的文件权限就出现错乱了demo 2server#include iostream #include unistd.h #include sys/types.h #include sys/stat.h #include fcntl.h using namespace std; int main() { mkfifo(./pipe,0666); int fdopen(./pipe,O_WRONLY); int cnt 1; while(true) { sleep(1); write(fd,cnt,sizeof(cnt)); cout传输一个数据cntendl; cnt; } close(fd); return 0; }注意open的标志位不可以加O_TRUNC因为命名管道不支持而且也可以不加O_APPEND因为没有什么意义可以不加client#include iostream #include unistd.h #include sys/types.h #include sys/stat.h #include fcntl.h using namespace std; int main() { int fdopen(./pipe,O_RDONLY); int cnt 0; while(true) { sleep(1); read(fd,cnt,sizeof(cnt)); cout接收到一个数据cntendl; } close(fd); return 0; }4-2 理解命名管道命名管道是通过创建一个特殊的文件让这个文件的内容来作为进程间看到的同一份资源进行通信其实你会发现匿名管道和命名管道都是复用了文件系统来实现的只是他们一个是直接使用文件缓冲区不会创建磁盘文件但是命名管道是会创建磁盘文件的但是它们都不会将数据刷新到磁盘匿名管道是通过父子进程对于地址空间的拷贝找到同一个管道的那命名管道呢命名管道因为会在磁盘上创建文件并且它的属性中有它自己的名字所以这也可以复用文件系统路径唯一性来保证进程间访问的是同一个管道4-3匿名管道与命名管道的区别1 匿名管道由pipe函数创建并打开。2 命名管道由mkfifo函数创建打开用open3 FIFO命名管道与pipe匿名管道之间唯⼀的区别在它们创建与打开的方式不同一但这些工作完成之后它们具有相同的语义。4-3 命名管道的打开规则1 如果当前打开操作是为读而打开FIFO时1-1 O_NONBLOCK disable阻塞直到有相应进程为写而打开该FIFO1-2 O_NONBLOCK enable立刻返回成功2 如果当前打开操作是为写而打开FIFO时2-1 O_NONBLOCK disable阻塞直到有相应进程为读而打开该FIFO2-2 O_NONBLOCK enable立刻返回失败错误码为ENXIO4-4 命名管道的特性特性匿名管道一样但是有一点不同命名管道可以用来进行不相关的进程之间的通讯其他特性这里就不再赘述了。但是注意open再打开管道文件的时候都是默认阻塞的只有如果只有读写端一端开启的话就会阻塞再open只有都打开才会成功返回5 system V共享内存共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间这些进程间数据传递不再涉及到内核换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据5-1 什么是system Vsystem V是一种标准Linux内核支持了这种标准专门涉及了一个IPC通讯模块通信的接口设计和原理具有相似性。5-2 共享内存的原理因为IPC通信的本质是让不同的进程看见同一份资源而共享内存故名思意就是让两个进程看到同一个物理空间即共享内存5-3 理解共享内存1 这个物理内存通过平坦模式编址然后映射到各个进程的虚拟地址空间的用户共享区中所以我们访问这个共享的物理只需要通过使用虚拟地址就可以通过页表转换访问真实共享的物理内存2 开辟物理内存将物理内存映射到进程的虚拟地址空间中这些过程都是由OS来完成的就是系统调用我们用系统调用完成上述的操作3 当我们取消关联关系的时候由OS来释放内存4 可能同时存在由多组进程都在使用不同的共享内存来进行通信所以OS内有多个共享内存同时存在所以我们需要也需要通过先描述再组织这个方式来管理的。所以我们可以砍一下共享内存管理的数据结构来理解一下他5-4 共享内存的数据结构struct shmid_ds { struct ipc_perm shm_perm; /* operation perms */ int shm_segsz; /* size of segment(bytes) */ __kernel_time_t shm_atime; /* last attach time*/ __kernel_time_t shm_dtime; /* last detach time*/ __kernel_time_t shm_ctime; /* last change time*/ __kernel_ipc_pid_t shm_cpid; /* pid of creator */ __kernel_ipc_pid_t shm_lpid; /* pid of last operator */ unsigned short shm_nattch; /* no. of currentattaches */ unsigned short shm_unused; /* compatibility */ void shm_unused2; / ditto - used byDIPC */ void shm_unused3; / unused */ };5-5 共享内存函数shmget 函数功能⽤来创建共享内存 原型 int shmget(key_t key, size_t size, int shmflg); 参数 key:这个共享内存段名字通过ftok这个函数来获取 size:共享内存⼤⼩ shmflg:由九个权限标志构成它们的⽤法和创建⽂件时使⽤的mode模式标志是⼀样的 取值为IPC_CREAT共享内存不存在创建并返回共享内存已存在获取并返回。 取值为IPC_CREAT | IPC_EXCL共享内存不存在创建并返回共享内存已存在出错返回。 返回值成功返回⼀个⾮负整数即该共享内存段的标识码失败返回-1key值我们一般是通过ftok这个函数来让系统生成的。但是为什么要key呢因为不同的进程shm来进行通信所以需要标识内存的唯一性key来区分不是内核直接形成的而是在用户层构建并传入OS的。为什么要这样呢因为两个进程是相互独立的他们具有独立性这就意味着我们要访问同一个物理内存是需要标识但是由于独立性如果让OS来标识那么注定会有进程拿不到这个id所以让我们在用户层传入一个自定的key值然后两个进程传给操作系统相同的key经过运算shmget可以返回相同的id这样就让两个进程看到同一个物理内存了。这些都是共享内存函数中常见的标志位但是我们往往是组合使用的。IPC_CREAT创建共享内存如果目标共享内存不存在就创建否则打开这个已经存在的共享内存并且返回(这个进经常用来获取已经存在的目标共享内存)IPC_CREAT | IPC_EXCL | 权限位 :IPC_EXCL 单独使用往往没有意义所以经常是和IPC_CREAT一起使用的。如果你要创建的shm不存在就创建它如果已经存在shmget返回就会出错这个机制注定了用这个标志位shmget成功返回一定是一个全新的共享内存。因为共享内存也有权限并且在这个情况下只会返回全新的共享内存所以往往这些标志位都是和权限位例如0666 (0表示8进制详情请见上位对于权限位传入的理解)。所以这个参数常常是用来创建全新的共享内存的shmat函数功能将共享内存段连接到进程地址空间 原型 void *shmat(int shmid, const void *shmaddr, int shmflg); 参数 shmid: 共享内存标识 shmaddr:指定连接的地址如果不指定地址设为NULL就可以 shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY,一般直接设置为0默认设置就可以了 返回值成功返回⼀个指针指向共享内存第⼀个节失败返回-1其实这个函数和malloc函数很像因为堆的使用其实和共享内存虚拟地址空间使用是类似的.因为读写共享内存并没有用系统调用共享区属于用户空间可以让用户直接使用说明shmaddr为NULL核心自动选择⼀个地址shmaddr不为NULL且shmflg无SHM_RND标记则以shmaddr为连接地址。shmaddr不为NULL且shmflg设置了SHM_RND标记则连接的地址会自动向下调整为SHMLBA的整数倍。公式shmaddr - (shmaddr % SHMLBA) shmflgSHM_RDONLY表示连接操作用来只读共享内存shmdt函数功能将共享内存段与当前进程脱离 原型 int shmdt(const void *shmaddr); 参数 shmaddr: 由shmat所返回的指针 返回值成功返回0失败返回-1 注意将共享内存段与当前进程脱离不等于删除共享内存段shmctl函数功能⽤于控制共享内存 原型 int shmctl(int shmid, int cmd, struct shmid_ds *buf); 参数 shmid:由shmget返回的共享内存标识码 cmd:将要采取的动作有三个可取值 buf:指向⼀个保存着共享内存的模式状态和访问权限的数据结构 返回值成功返回0失败返回-1注意进程结束了如果没有进行删除共享内存共享内存资源会一直存在因为共享内存的资源生命周期随内核如果没有显示的删除即使进程退出了IPC资源依旧不会被删除。5-6 共享内存的优缺点优点共享内存是进程间通信中 速度最快的方式1 映射之后读写直接被对方看到2 不需要进行系统调用获取或者写入内容缺点1 通信双方没有所谓的“同步机制”导致数据不一致2 共享内存没有保护机制

相关新闻

机械工具检测数据集VOC+YOLO双格式一致性校验指南

机械工具检测数据集VOC+YOLO双格式一致性校验指南

简介:本资源是面向计算机视觉初学者与工业检测算法开发者的小型机械工具目标检测数据集,覆盖crowbar、hammer、screwdriver等8类常见维修工具,适用于YOLO系列与Faster R-CNN等主流检测模型的训练与验证。数据集提供4713张高质量JPG图像及严格…

2026/10/11 8:21:26 阅读更多 →
YOLO自动化训练平台:工业级图像检测全链路工程化实践

YOLO自动化训练平台:工业级图像检测全链路工程化实践

简介:YOLO图像检测自动化训练平台是一套面向人工智能初学者与计算机视觉开发者的轻量级YOLO模型训练工具,旨在降低深度学习图像识别的使用门槛,解决手动编写训练脚本、配置环境、管理数据流程等重复性难题。资源共53个文件,涵盖22…

2026/10/11 8:21:26 阅读更多 →
云平台矩阵:跨浏览器测试的自动化方案与实践

云平台矩阵:跨浏览器测试的自动化方案与实践

做前端的人最怕听到一句话:“我这边浏览器打开是好的啊。”用户不会告诉你他用的是哪个浏览器哪个版本,也不会告诉你是在Windows上还是在MacBook上,更不会告诉你屏幕是多宽。跨浏览器测试这件事,说得实在一点,就是一场…

2026/10/11 8:20:25 阅读更多 →

最新新闻

Motrix 仓库语言与文档规范:双语发布、公私边界与 Obsidian 文档网关实战

Motrix 仓库语言与文档规范:双语发布、公私边界与 Obsidian 文档网关实战

桌面应用网络后端 【免费下载链接】Motrix A full-featured download manager. 项目地址: https://gitcode.com/GitHub_Trending/mo/Motrix 点击查看 免费下载 本文围绕 Motrix 开源仓库的 .claude/rules/language-and-docs.md 规则文件展开,系统讲解该…

2026/10/11 11:39:11 阅读更多 →
CAN总线仲裁机制详解:从显性位到机器人关节ID分配实战

CAN总线仲裁机制详解:从显性位到机器人关节ID分配实战

1. 从一次关节抖动说起:为什么两个节点同时开口会出事如果你正在做机器人关节控制,大概率遇到过这种场景:一条CAN总线上挂着主控和好几个关节驱动器,主控周期性下发位置指令,某个关节驱动器同时上报状态反馈&#xff0…

2026/10/11 11:39:11 阅读更多 →
CAN总线八字节协议解析:关节电机控制帧与反馈帧实战指南

CAN总线八字节协议解析:关节电机控制帧与反馈帧实战指南

1. 为什么八字节值得单独拎出来讲搞机器人关节控制的人,绕不开CAN总线。但很多人第一次看到关节驱动器的通信协议文档时,脑子里冒出来的第一个问题往往是:八个字节,到底能装下什么?你想想,一个电机要控制的…

2026/10/11 11:39:11 阅读更多 →
RK3588三系统Ubuntu适配实战:22.04/24.04/26.04刷机与选型指南

RK3588三系统Ubuntu适配实战:22.04/24.04/26.04刷机与选型指南

1. 从一块RK3588开发板说起:为什么三系统适配值得单独聊手里有一块RK3588的开发板,第一件事做什么?绝大多数人的答案都是"刷个系统跑起来看看"。但真正上手之后你会发现,刷系统这件事远没有想象中那么"一次就好&qu…

2026/10/11 11:39:11 阅读更多 →
机器人关节CAN总线控制协议详解:8字节帧结构与通信层实现

机器人关节CAN总线控制协议详解:8字节帧结构与通信层实现

1. 从八个字节说起:为什么CAN协议是机器人关节控制的命脉搞机器人关节控制的人,绕不开一个东西——CAN总线。尤其是做协作机器人、四足机器人、外骨骼这类多关节协同的设备,几乎每个关节的驱动器都挂在同一条CAN总线上。你手里拿着主控板&…

2026/10/11 11:39:11 阅读更多 →
海康工业相机C# SDK开发实战:从示例工程到产线稳定取流

海康工业相机C# SDK开发实战:从示例工程到产线稳定取流

简介:这份资源是面向工业视觉方向C#开发者的海康工业相机SDK示例程序包,适合刚接触相机二次开发、需要快速跑通设备连接与图像采集流程的工程师与学习者。压缩包共29个文件,约518KB,以cs源码、sln与csproj工程文件、exe可执行程序…

2026/10/11 11:38:11 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →