进程间通信(管道)

进程间通信

进程间通信,即IPC(I nter P rocess C ommunication),在学习进程时,我们知道进程是具有独立性的,两个进程之间无法直接进行信息传递。为了实现进程间通信,人们创造除了许多方法,比如管道,共享内存等,本文旨在理清这些通信方法的原理。

对于进程间通信,我们应该始终关注一个根本性的概念:进程间通信,本质是让两个进程看到同一份资源。

管道

管道分为匿名管道 和命名管道,但其实它们之间差别并不是很大,理解其中一个便可以理解另一个。

匿名管道

匿名管道只能用于父子间通信。先概述一下原理:

首先,父进程通过 pipe 函数创建一个管道,管道本质是一个特殊的文件,父进程有两个文件描述符会指向它(一个读,一个写)。

然后,父进程创建子进程,因为子进程会继承父进程的文件描述符表,所以其中也会有两个文件描述符指向管道文件。

最后,父进程关闭其中一个文件描述符,比如关闭表示 "读" 的文件描述符,而子进程关闭表示 "写" 的文件描述符。这样,父进程可以对管道进行 "写入信息" 的操作,子进程可以对管道进行 "读出信息" 的操作。

命名管道

匿名管道只能用于父子进程之间,而命名管道可以用于任意两个进程之间。

命名管道的原理与匿名管道的一致,所以对于原理不过多赘述,但有些问题值得讨论。

前面说管道通信的本质是让两个进程看到同一个文件,父子进程之间通过继承文件描述符表的方式看到同一个文件,那两个陌生进程怎么保证看到同一个文件呢?

我们先来看例子:

可以看到,我们在一端创建管道时要准备好管道的路径信息,然后另一端再根据路径找到管道。

匿名管道和命名管道的差异

匿名管道和命名管道除了使用场景,只剩创建方式不同 ,匿名管道使用 pipe 创建,而命名管道使用 mkfifo 创建。我们来看看它们的函数原型:

pipefd2为传出参数,pipefd0是读端,pipefd1是写端。

pathname是要创建的管道文件名,mode是文件的权限。

在创建与打开管道的工作结束后,匿名管道和命名管道就具有相同的语义了。

管道的一些特性

同步机制

管道文件,自带同步机制。内核自动帮你处理好读写两端的阻塞和等待,保证数据的有序、安全传递,不需要你手动加锁或信号量。

存在以下4种通信情况:

1.写端慢 ,读端快:读端阻塞,等待写端。

2.写端快 ,读端慢:当缓冲区满了,写端阻塞,等待读端。

3.写端关闭 ,读端继续:读端一直读,直到 read 返回 0,表示读到文件结尾。

4.写端继续 ,读端关闭:无意义,操作系统杀掉写端。

单项通信

前面说管道是半双工的,什么叫半双工呢?

半双工即同一时间只能单向传输,比如 A 和 B 进行通话:A 说话时,B 只能听,如果 B 想说话,就必须先等 A 说完。

除了半双工,还有单工 和全双工 。单工是一端只能听,不能说,另一端相反 。而全双工是同一时间可以双向通信。

注意后面说的两种通信方式不是管道的特性啊!管道只是半双工的!

生命周期

管道(管道文件)的生命周期是随进程的,也就是进程结束它就关闭了。

面向字节流

管道是面向字节流的。管道里的数据是一串连续的 "字节流",没有固定的 "消息边界",读和写的次数不一定对应,内核不帮你区分 "哪段是第一条消息、哪段是第二条"。

比如写端的本意是传输:AA BB CC(两个单词为一组),但是传输进入管道的数据是 A A B B C C,读端不知道写端的本意,可能会读成 AAB BCC(三个单词为一组)之类的。

如果想要解决这个问题,我们可以使用手动加分隔符 ,或者先传入读取规则(读取长度)再传入数据等方法。又或者,我们直接换一种IPC实现方式(见下篇)。

相关推荐
叼烟扛炮几秒前
[LangChain] 学习笔记(05):提示词模板(Prompt)与少样本注入(Few-Shot)实战
linux·人工智能·笔记·学习·langchain·prompt
CodeYp20194 分钟前
第5讲:Socket 编程 TCP
linux·socket·tcp
咔_13 分钟前
有IPv6地址,为什么外面还是连不进来?让同一台服务分别卡在四个位置
linux·计算机网络
CodeYp201929 分钟前
第3讲:网络命令
linux·网络·命令
一个天蝎座 白勺 程序猿9 小时前
KingbaseES数据库归档重做日志文件管理:从配置到运维的实战指南
运维·数据库·oracle·kingbasees·金仓数据库
天诰12 小时前
SA-K-11 检索会消失吗与四个未解问题
java·服务器·人工智能·python·机器学习·ai编程
2035去旅行13 小时前
bootcmd 详细讲解
linux·嵌入式·arm·soc
分布式存储与RustFS13 小时前
镜像仓库的层别堆本地盘:用 RustFS 给 Docker Registry 当 S3 后端
运维·云原生·开源·对象存储·分布式存储·s3·性能基准
陈希12313 小时前
Linux 防火墙配置实战:firewalld、iptables 与云安全组
linux·运维·服务器
女神下凡14 小时前
芯参谋(95):嵌入式文件系统_开发指南
linux·服务器·arm开发·驱动开发·设计规范