由于各个进程之间独享一块用户地址空间,一般而言这块独立的用户地址空间不能互相访问,所以进程之间想要通信必须通过内核空间(每个进程共享)。
进程间的通信方式主要有以下几种:
管道 消息队列 共享内存 信号量 信号Socket
管道
管道的数据传输方向是单向的,如果两个进程之间需要互相传递数据,那么需要创建两个管道才可以。
管道主要分为: 匿名管道 命令管道匿名管道
匿名管道只适合具有父子关系的进程间通信,创建需要通过下面的系统调用来实现:
int pipe(int fd[2])
这里表示创建一个匿名管道,并返回了两个描述符,fd[0]是管道读取端描述符,fd[1]是管道写入端描述符。匿名管道只存在于内存中,不存在于文件系统。
这里的管道就是内核里面的一串缓存。管道传输的数据无格式但是大小受限。
父子进程间如何使用匿名管道通信
我们需要通过fork来创建子进程,创建的子进程会复制父进程的文件描述符,这样父子进程之间都会有fd[0]和fd[1],父子进程通过各自的fd写入和读取同一个管道文件就可以实现跨进程通信。
由于父子进程都可以对管道进行读写,为了避免这种情况的发生,通常我们会做以下操作:
父进程关闭读取的fd[0],只保留写入的fd[1]
子进程关闭写入的fd[1],只保留读取的fd[0]
所以如果需要进行双向通信,必须要建立两个管道。
shell中的A|B管道操作有什么特别?
ps aux | grep mysql
Linux上述命令|是一个管道,它的功能是将前一个命令的输出当做后一个命令的输入。但是在执行上述命令(A|B)时,由于A进程和B进程都是由shell创建出来进程,A和B之间不存在父子关系,它们父进程都是shell。它的管道读写图如下:
命名管道
命名管道可以在不相关的进程之间能互相通信,因为命令管道需要提前创建一个类型为管道的设备文件,在进程里只要使用这个设备文件,就可以互相通信。
创建管道文件mkfifo test_pipe
向管道写入数据echo "hello pipe" > test_pipe
在写入数据以后,命令停在此处,是因为管道里的内容没有被读取,只有当管道里的命令被读取以后,命令才可以正常退出。
读取管道命令cat test_pipe
可以看到在执行cat读取命令以后,内容被读取出来打印在终端上,另一方面写入指令echo也正常退出。