pipe , 中文翻译为管道,是 Unix/Linux 系统中一种比较常用的 IPC(Inter Process Communication) 。下面这组 shell 命令,估计大部分人都用过或者见过。
ls | wc -l
ls 和 wc 分别是两个独立的进程。shell 会将 ls 的输出结果作为 wc 的输入结果,然后再由 wc 把处理结果投放到终端上。
上图很生动地描绘出这组命令的工作流程。pipe 就像一根圆管,ls 的输出内容流入到圆管的一端 (标准输出)。随后,内容一直流到圆管的另一端 (标准输入) 由 wc 接收。这跟圆管只接受 byte stream,也就是说消息内容是无边界的。
#include <unistd.h>
int pipe(int[2] pfd);
我们需要向 pipe() 传入一个大小为 2 的数组,与此同时内核会维护一个临时的 buffer,也就是看不见摸不着的管道。随后,内核会返回管道的读端和写端的文件描述符,它们分别存放于参数数组的第 0 个元素和第 1 个元素。
之所以叫 IPC, 顾名思义,管道就是用来让两个或者多个进程之间通信,尽管多个进程共享一个管道的情况十分少见,但我们并未被禁止这样做,但我们在大多数情况都绝不应该这样做。 管道有两端,一端为写端,另一端为读端。如果一个进程试图往一个空的管道读取数据,那么该进程将会被堵塞,直至管道非空为止。同理,如果一个进程尝试往一个已满的管道塞入更多的内容,此进程一样会被堵塞,直到管道为非满状态。
调用 pipe()
,再调用 fork()
。尽管,管道是在父进程创建的,但是子进程以拷贝的形式继承父进程的 open file descriptors 。
#include <unistd.h>
#include <iostream>
const int BUFF_SIZE = 11;
int main()
{
int pfd[2];
if (pipe(pfd) == -1)
printf("failed to create a pipe");
switch (fork())
{
case -1:
printf("failed to create a process");
case 0:
if (close(pfd[1]) == -1)
_exit(1);
char read_buff[BUFF_SIZE];
int readn = read(pfd[0], read_buff, BUFF_SIZE);
printf("child process read: %s\n", read_buff);
_exit(0);
}
if (close(pfd[0]) == -1)
exit(1);
char write_buff[] = "hello world";
int writen = write(pfd[1], write_buff, BUFF_SIZE);
exit(0);
}
输出结果:
[me@localhost Documents]$ ./exe
child process read: hello world
如果子进程是负责读,而父进程负责写的话。那么子进程在读之前必须关闭管道的写端,父进程同样地必须关闭管道的读端。不然就会形成了闭环。
想要正确使用管道就必须避免出现 (a) 这种情况。每个文件描述都有一个引用计数,在 (a) 的情况下,尽管父进程已经向管道输入完毕并且正确关闭掉管道的读写端,然而子进程不会收到 EOF,那么子进程会永远阻塞下去。
switch (fork())
{
case -1:
printf("failed to create a process");
case 0:
// if (close(pfd[1]) == -1)
// _exit(1);
char read_buff[BUFF_SIZE];
int readn;
while (readn = read(pfd[0], read_buff, BUFF_SIZE) != 0)
{
printf("child process read: %s\n", read_buff);
}
_exit(0);
}
if (close(pfd[0]) == -1)
exit(1);
char write_buff[] = "hello world";
int writen = write(pfd[1], write_buff, BUFF_SIZE);
close(pfd[1]);
管道的原理和使用方法都特别简单,但一定要避免出现关闭。也尽量不要有一个以上的进程共享读端或者写端,不然就会出现条件竞争。
参考
[^1] 44.2 Figure 44-2, The Linux Programming Interface
[^2] 44.2 Figure 44-3, The Linux Programming Interface
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。