likes
comments
collection
share

进程之间的通讯方式?

作者站长头像
站长
· 阅读数 8

进程之间的通讯方式?

可以介绍一下进程的通信方式有哪些吗?


好的,面试官 我们常说的进程之间的通信方式有 7 种,分别是匿名管道、命名管道、消息队列、共享内存、信号量、信号以及Socket。

那下面我就详细介绍一下每一种通信方式的异同吧,如果在我介绍的过程中,你有任何问题想问我,都可以打断我的。


第一种,匿名管道

顾名思义,它是一种没有名字的管道,但它确实我们最经常接触到的, 比如我们在 linux 系统在使用的ps auxf | grep nignx 命令,其实中间的竖线“|”就是匿名管道, 因为是匿名,所以该管道只能用于具有亲缘关系的进程(父子、兄弟)之间,而无法被其他进程所使用, 该命令执行完后,即被销毁。

它的数据是只能单向传输,在创建匿名管道的时候底层实际上是调用了 pipe() 系统调用, 它会返回两个文件描述符,分别用作管道的读取端和写入端;这时候 fork 出子进程,所以父子进程都同时具有了两个文件描述符,即读取端和写入段;但是又因为管道是单向传输的, 所以父子进程需要各关闭一端,比如父进程关闭读端,则子进程需要关闭写端。

刚有介绍了匿名管道在父子进程间通信,那么兄弟进程间的呢? 其实这个我们也经常接触到的,就是当我们在 shell 中执行 ps auxf | grep nignx 命令的时候, 实际上是兄弟进程在通过匿名管道在通信, 因为命令是在 shell 上执行的,所以 fork 的两个进程都是 shell 进程的子进程。

接着,第二种,命名管道

命名管道是由名字的,它通过 mkfifo 来创建,会在系统中实际创建一个管道文件,对各进程可见; 但是命名管道是阻塞写的,一旦往管道里写入数据,写端阻塞,只有读取了数据,才能继续写入。

所谓管道就是内核里面的一串缓存,通过管道传输的数据是无格式的流且大小受限。 综上,可以看到无论是匿名管道还是命名管道,它们的通信效率都不高,不适合进程间的频繁通信。

第三种通信方式——消息队列

对于管道的这个问题,我们的第三种通信方式——消息队列就可以解决。 消息队列实际上是内核中的一个消息链表,进程 A 只需要把消息放进链表中即可返回,进程 B 在有需要的时候就去取即可。 要满足这一点,就要求进程们放的消息不是随便的,它需要发送方和接收方提前约定好的。 所以呢,消息队列会有通信不及时的缺点,而且它的每个消息体都是有一定的大小限制的, 这就说明它是不适合大数据传输的。 当然啦,消息队列最大的一个缺点就是在通信的过程中,存在用户态与内核态之间的数据拷贝开销。

第四种通信方式——共享内存

为了解决数据拷贝的开销,我们就来到了第四种通信方式——共享内存! 其实共享内存也很好理解, 原来进程间是隔离的,采用了共享内存之后,会将一块虚拟地址空间映射到相同的物理内存中, 一个进程往里面写数据,另一个进程立马就可以感知到了,不需要拷来拷去的。

然而共享内存虽然快捷了,但是也引进来了新的问题, 假如两个进程同时往一个地方写数据怎么办?这就出现了多进程竞争共享资源的问题,

第五种通信方式了——信号量

为了解决这个问题,就得引出第五种通信方式了——信号量。 其实信号量,和我们平时接触到的锁很像,它标志着共享资源有多少,即有多少个进程可以同时占用, 这里面就是一堆的 PV 操作了,进程只有 P 成功了,才可以继续操作。

第六种通信方式——信号

以上介绍的都是进程通信的正常情况,那当然也有一些异常情况了, 异常情况就需要用到第六种通信方式——信号了,比如中断信号,Ctrl+C

第七种通信方式—— socket

上面介绍的都是同一主机的进程间通信,如果是不同网络的不同主机间的进程通信就需要用到第七种通信方式—— socket 了 socket 的通信方式也有多种 TCP、UDP、本地socket。


我的回答就这些,感谢面试官的聆听。