管道(Pipe)是UNIX系统进程间通信的一种古老形式,所有类UNIX系统(Linux,Qnx等)都支持这种IPC机制。管道分为无名管道和命名管道(FIFO),它们都是半双工的通信方式,一个进程对管道进行写操作,另外一个进程对管道进行读操作。
无名管道只能用于具有亲缘关系的进程间的通信,比如父子进程之间或者父进程的两个子进程之间的通信,原因是无名管道创建的文件描述符并不指向文件系统,而是由内核缓冲区来实现,因此对没有亲缘关系的进程不可见。而命名管道(FIFO)则没有这种限制,我们下次再来介绍命名管道(FIFO)。
管道通过调用pipe函数来创建,创建成功之后会返回两个文件描述符,fd[0]指向管道的读端,fd[1]指向管道的写端。
#include <unistd.h>
int fd[2];
pipe(fd);
单个进程中的管道几乎没什么用处,通常进程会先调用pipe创建管道,然后调用fork,从而创建父子进程之间的管道通信。下图体现了管道创建后的数据可能的流向,fork创建子进程时子进程会继承父进程的文件描述符,因此父子进程都拥有fd[0]和fd[1]两个文件描述符。
fork之后做什么取决于我们想要数据按照什么方向流动。对于从父进程到子进程的管道,父进程关闭管道的读端fd0,子进程关闭管道的写端fd1,下图体现了从父进程到子进程的管道。对于从子进程到父进程的管道,父进程关闭管道的写端fd1,子进程关闭管道的读端fd0。
当管道的一端被关闭后,有下面两种情况:
1)当读(read)一个写端被关闭的管道时,在管道中的所有数据都被读取后,read返回0,表示文件结束。
2)当写(write)一个读端被关闭的管道时,会产生信号SIGPIPE。如果忽略该信号或者捕捉该信号并从其他处理程序返回,则write返回-1,errno设置为EPIPE。
下面是一个无名管道的实例,用来实现两个子进程向管道写入数据,父进程从管道读出数据。
想获取无名管道的代码实例请关注微信公众号“汽车软件后花园”,回复0912获取文章链接。