初学操作系统的时候,我就一直懵逼,为啥进程同步与互斥机制里有信号量机制,进程通信里又有信号量机制,然后你再看网络上的各种面试题汇总或者博客,你会发现很多都是千篇一律的进程通信机制有哪些?进程同步与互斥机制鲜有人问津 。看多了我都想把 CSDN 屏了.....,最后知道真相的我只想说为啥不能一篇博客把东西写清楚,没头没尾真的浪费时间 。
希望这篇文章能够拯救某段时间和我一样被绕晕的小伙伴 。上篇文章我已经讲过进程间的同步与互斥机制,各位小伙伴看完这个再来看进程通信比较好 。
全文脉络思维导图如下:
文章插图
1. 什么是进程通信顾名思义,进程通信( InterProcess Communication,IPC)就是指进程之间的信息交换 。实际上,进程的同步与互斥本质上也是一种进程通信(这也就是待会我们会在进程通信机制中看见信号量和 PV 操作的原因了),只不过它传输的仅仅是信号量,通过修改信号量,使得进程之间建立联系,相互协调和协同工作,但是它缺乏传递数据的能力 。
虽然存在某些情况,进程之间交换的信息量很少,比如仅仅交换某个状态信息,这样进程的同步与互斥机制完全可以胜任这项工作 。但是大多数情况下,进程之间需要交换大批数据,比如传送一批信息或整个文件,这就需要通过一种新的通信机制来完成,也就是所谓的进程通信 。
再来从操作系统层面直观的看一些进程通信:我们知道,为了保证安全,每个进程的用户地址空间都是独立的,一般而言一个进程不能直接访问另一个进程的地址空间,不过内核空间是每个进程都共享的,所以进程之间想要进行信息交换就必须通过内核 。
文章插图
下面就来我们来列举一下 linux 内核提供的常见的进程通信机制:
- 管道(也称作共享文件)
- 消息队列(也称作消息传递)
- 共享内存(也称作共享存储)
- 信号量和 PV 操作
- 信号
- 套接字(Socket)
$ command1 | command2
以上这行代码就组成了一个管道,它的功能是将前一个命令(command1)的输出,作为后一个命令(command2)的输入,从这个功能描述中,我们可以看出管道中的数据只能单向流动,也就是半双工通信,如果想实现相互通信(全双工通信),我们需要创建两个管道才行 。另外,通过管道符 | 创建的管道是匿名管道,用完了就会被自动销毁 。并且,匿名管道只能在具有亲缘关系(父子进程)的进程间使用,。也就是说,匿名管道只能用于父子进程之间的通信 。
在 Linux 的实际编码中,是通过 pipe 函数来创建匿名管道的,若创建成功则返回 0,创建失败就返回 -1:
int pipe (int fd[2]);
该函数拥有一个存储空间为 2 的文件描述符数组:- fd[0] 指向管道的读端,fd[1] 指向管道的写端
- fd[1] 的输出是 fd[0] 的输入
1)父进程创建两个匿名管道,管道 1(fd1[0]和 fd1[1])和管道 2(fd2[0] 和 fd2[1]);
因为管道的数据是单向流动的,所以要想实现数据双向通信,就需要两个管道,每个方向一个 。2)父进程 fork 出子进程,于是对于这两个匿名管道,子进程也分别有两个文件描述符指向匿名管道的读写两端;
3)父进程关闭管道 1 的读端 fd1[0] 和 管道 2 的写端 fd2[1],子进程关闭管道 1 的写端 fd1[1] 和 管道 2 的读端 fd2[0],这样,管道 1 只能用于父进程写、子进程读;管道 2 只能用于父进程读、子进程写 。管道是用环形队列实现的,数据从写端流入从读端流出,这就实现了父子进程之间的双向通信 。
文章插图
看完上面这些讲述,我们来理解下管道的本质是什么:对于管道两端的进程而言,管道就是一个文件(这也就是为啥管道也被称为共享文件机制的原因了),但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在于内存中 。
简单来说,管道的本质就是内核在内存中开辟了一个缓冲区,这个缓冲区与管道文件相关联,对管道文件的操作,被内核转换成对这块缓冲区的操作 。
推荐阅读
- 六大茶叶价格或将上涨,价格难以预料
- 六大茶类与茶点的搭配,是怎么来的
- 六大茶山的茶之道,古六大茶山古六大茶山系列之莽枝古树茶
- 六大类茶叶的初制过程,黑茶初制与绿茶初制的区别
- 六大古茶山曼撒茶山,新品2015年老同志易武正山生茶100克上市
- Linux怎么查看进程资源使用情况
- 六大茶类的功效与禁忌,胖大海的禁忌与功效作用
- 如何保证APP与API通信安全,TOKEN冒用带来的风险很大?
- 莽枝红土坡普洱茶,云南普洱茶产于六大茶山
- 六大茶山企业文化,古六大茶山古六大茶山系列之莽枝古树茶