语法
#include <unistd.h>
int pipe(int pipefd[2]);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <fcntl.h> /* Obtain O_* constant definitions */
#include <unistd.h>
int pipe2(int pipefd[2], int flags);
描述
pipe()
创建一个单向的可用作进程间通信的数据通道。pipefd
数组用作返回管道两端的文件描述符。pipefd[0]
代表管道的读取端。pipefd[1]
用作写入端。数据被写入到由内核所缓冲的管道写入端。
如果 flags
为 0,那么pipe2()
就和pipe()
一样。下面这些变量可以在flags
中按位或运算来获得不同的功能:
O_CLOEXEC
为两个文件描述符设置close-on-exec (FD_CLOEXEC)
标志。在 open 中查看相同标志的描述,了解它为什么非常有用。
O_DIRECT( 自从 Linux 3.4 )
创建一个在 packet 模式下执行 I/O 的管道。每次对管道的 write 都被当作分开的包处理,并且每次从管道中 read 都会依次读取一个包。注意以下几点:
- 写入超过 PIPE_BUF 字节(查看 pipe(7))将会分为多个包。常数 PIPE_BUF定义在
<limits.h>
中。 - 如果 read 确定的缓冲区大小比下一个包小,这时,包中需要的字节被读取,超出的字节被丢弃。指定缓冲区大小为 PIPE_BUF 就足以读取尽可能大的包。
- 不支持 0 长度的包。(read 指定缓冲区大小为 0 是一个空操作,返回 0。)
老版本内核不支持这个标志将会通过 EINVAL 错误指出。
自从 Linux 4.5,可以通过 fcntl 改变管道文件描述符的 O_DIRECT 设置。
O_NONBLOCK
为两个新开的文件描述符设置 O_NONBLOCK 文件状态标志。使用这个标志节省额外的 fcntl 调用以达到同样的效果。
返回值
成功,返回 0。错误,返回 -1 并且设置 errno。
在 Linux 上(和其他的系统),pipe()不在失败时修改pipefd。在 POSIX.1-2016 中添加了规范这一行为的要求。Linux 规定的 pipe2() 系统调用同样在失败时不修改 pipefd。
错误
- EFAULT 无效 pipefd
- EINVAL(pipe2())flags 值非法
- EMFILE 达到之前进程所限制的打开文件描述符的数目
- ENFILE 达到系统所限制的打开文件描述符的数目
- ENFILE 管道空间达到用户强行限制的内存,或者调用者没有权限。查看pipe(7)
版本
pipe2()在 Linux 2.6.27 中被添加进去;glibc 支持从 2.9 版本后开始。
标准
pipe(): POSIX.1-2001,POSIX.1-2008。
pipe2() 是 Linux 特有。
范例
下面的程序创建一个管道,然后 frok 去创建一个子进程。子进程继承了一套指向同一管道的文件描述符。fork 之后,每个进程关闭了管道不需要的文件描述符。父进程这时写入管道从命令行参数获取的字符串,然后子进程依次按字节读取这个字符串并显示在标准输出上。
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int
main(int argc, char *argv[])
{
int pipefd[2];
pid_t cpid;
char buf;
if (argc != 2) {
fprintf(stderr, "Usage: %s <string>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Child reads from pipe */
close(pipefd[1]); /* Close unused write end */
while (read(pipefd[0], &buf, 1) > 0)
write(STDOUT_FILENO, &buf, 1);
write(STDOUT_FILENO, "\n", 1);
close(pipefd[0]);
_exit(EXIT_SUCCESS);
} else { /* Parent writes argv[1] to pipe */
close(pipefd[0]); /* Close unused read end */
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}
}
via: http://man7.org/linux/man-pages/man2/pipe.2.html
译者:LuuMing