第15章 进程间通行 15.2管道

<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)

通过管道也可以实现父进程与子进程间的同步。

转载于:https://my.oschina.net/u/2463708/blog/516227

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值