<430>
(1)管道的局限性
1)历史上,它们是半双工的。我们不应假定系统支持全双工的管道。
2)管道只能在具有公共祖先的两个进程之间使用。如父子进程。
//经由管道从父进程向子进程传送数据
#include "apue.h"
int
main(void)
{
int n;
int fd[2];
pid_t pid;
char line[MAXLINE];
if (pipe(fd) < 0)
err_sys("pipe error");
if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid > 0) { /* parent */
close(fd[0]);
write(fd[1], "hello world\n", 12);
} else { /* child */
close(fd[1]);
n = read(fd[0], line, MAXLINE);
write(STDOUT_FILENO, line, n);
}
exit(0);
}
(2)创建管道函数
int pipe(int pipefd[2]);
pipefd[0]用于读管道,pipefd[1]用于写管道。
POSIX.1允许实现支持全双工管道。对于这些实现,pipefd[0],pipefd[1]以读/写方式打开。
(3)
写管道时,常量PIPE_BUF规定了内核的管道缓冲区大小。
用pathconf或fpathconf函数可以确定PIPE_BUF的值。
此例子中子进程执行分页程序,其标准输入是管道的读端。父进程通过管道将文件内容复制到分页程序。
#include "apue.h"
#include <sys/wait.h>
#define DEF_PAGER "/bin/more" /* default pager program */
int
main(int argc, char *argv[])
{
int n;
int fd[2];
pid_t pid;
char *pager, *argv0;
char line[MAXLINE];
FILE *fp;
if (argc != 2)
err_quit("usage: a.out <pathname>");
if ((fp = fopen(argv[1], "r")) == NULL)
err_sys("can't open %s", argv[1]);
if (pipe(fd) < 0)
err_sys("pipe error");
if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid > 0) { /* parent */
close(fd[0]); /* close read end */
/* parent copies argv[1] to pipe */
while (fgets(line, MAXLINE, fp) != NULL) {
n = strlen(line);
if (write(fd[1], line, n) != n)
err_sys("write error to pipe");
}
if (ferror(fp))
err_sys("fgets error");
close(fd[1]); /* close write end of pipe for reader */
if (waitpid(pid, NULL, 0) < 0)
err_sys("waitpid error");
exit(0);
} else { /* child */
close(fd[1]); /* close write end */
if (fd[0] != STDIN_FILENO) {
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
err_sys("dup2 error to stdin");
close(fd[0]); /* don't need this after dup2 */
}
/* get arguments for execl() */
if ((pager = getenv("PAGER")) == NULL)
pager = DEF_PAGER;
if ((argv0 = strrchr(pager, '/')) != NULL)
argv0++; /* step past rightmost slash */
else
argv0 = pager; /* no slash in pager */
if (execl(pager, argv0, (char *)0) < 0)
err_sys("execl error for %s", pager);
}
exit(0);
}
(1)
int ferror(FILE *stream);
The function ferror() tests the error indicator for the stream pointed to by stream, returning nonzero if it is set. The error indicator can be reset only by the clearerr() function.
若流出错返回非0。
(2)
if (fd[0] != STDIN_FILENO) {
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
err_sys("dup2 error to stdin");
close(fd[0]); /* don't need this after dup2 */
}
int dup2(int oldfd, int newfd);
复制一个现有的文件描述符,newfd指定新描述符的值。返回新的文件描述符。
调用dup2和close将一个描述符复制到另一个上,都要先将两个描述符进行比较。(若oldfd等于newfd则返回newfd,而不关闭它。最后close将关闭该描述符)
(3)
char *getenv(const char *name);此处使用环境变量PAGER获得用户分页程序名称。这是环境变量的常用方法。
The getenv() function searches the environment list to find the environment variable name, and returns a pointer to the corresponding value string.
(4)
char *strrchr(const char *s, int c);
The strrchr() function returns a pointer to the last occurrence of the character c in the string s.
(1)
通过管道也可以实现父进程与子进程间的同步。