简介
先来了解什么是进程间通信。每个进程的用户地址空间是相互独立的,内核空间是共享的。所以进程之间必须通过内核来进行通信。而进程间通信方式通常有六种:管道,消息队列,共享内存,信号量,信号,socket。简单介绍一下这六种方式。
- 管道:两个进程通过对管道的两端进行读写来完成通信。
- 消息队列:消息队列是内核中的消息链表,通过用户自定义的数据类型向消息链表读写。
- 共享内存:进程的内存空间为虚拟地址,将进程的虚拟地址映射到同一块物理地址即可实现通信的效果。
- 信号量:这个实际上是为了解决共享内存的同步互斥问题。
- 信号:信号是进程唯一的异步通信机制,进程收到信号执行对应的信号处理函数。
- Socket:Socket可以实现不同主机上的进程间通信,通过网络传输数据。
本篇文章着重介绍管道,其他通信方式后续再介绍。
管道
管道有两种,命名管道和无名管道,在Linux系统中 |
为无名管道,例如 ps auxf | grep mysql
可以将前一个命令的输出作为后一个命令的输入。不过管道传输数据是单向的,双向通信需创建两个管道。而命名管道顾名思义就是自己创建管道,可以用mkfifo myPipe
命令创建管道文件,然后可以对他进行读写,例如:
echo "hello" > myPipe #将hello输入到myPipe文件中
#命令行阻塞了,因为管道内的数据被读取才能正常退出
cat < myPipe #读取管道数据
hello
而在实际项目应用中是通过这个函数来使用管道的int pipe(int fd[2])
该函数创建了一个管道并返回两个文件描述符,分别是fd[0]
管道的读端,fd[1]
管道的写端。那么它是如何实现进程间的通信呢,我们可以使用fork()
来创建子进程,因为创建的子进程会复制父进程的所有东西除了进程号,其中就包括了文件描述符。所以子进程也有能通过文件描述符来读写这个管道。如图所示:
为了避免两个进程同时读写,可以选择关闭父进程的读端,保留写端,关闭子进程的写端,保留读端。这样就能实现两个进程之间的通信了。
不管是命名管道还是无名管道,都是遵循先进先出的规则,都是通过内核来读写数据,系统调用较多,效率较低。
参考文章:
进程间通信方式–小林coding