进程间通信--pipe

管道的两种局限性:

  • 历史上,他们是半双工的(即数据只能够在一个方向上流动). 现在某些系统也提供全双工管道,但是为了最佳的移植性,我们决不应该预先假定系统使用此特性
  • 他们只能够在具有公共祖先的进程间使用. 通常一个管道由一个进程创建, 然后该进程通过调用fork, 此后父,子进程之间就可以使用该管道

尽管有这两种局限, 但半双工管道仍然是最常用的 IPC 形式.

管道由调用pipe函数创建:

#include<unistd.h>

int pipe(int filedes[2]); 

返回值: 0: 成功, -1: 失败

经由参数filedes返回的两个文件描述符:

filedes[0]: 读

filedes[1]: 写

filedes[1]的输出既是filedes[0]的输入

由此, 调用fork之后做什么取决于我们想要有的数据流动方向. 对于从父进程到子进程的管道, 父进程关闭管道的读端filedes[0], 子进程则关闭写端filedes[1]. 如代码所示:

/*******************************************************************************
* 版权所有:
* 模 块 名:
* 文 件 名:pipe.c
* 实现功能:
* 作    者:XYZ
* 版    本:V1.0
* 日    期:2013.08.19
* 其他说明:创建一个从父进程到子进程的管道,并且父进程经改管道向子进程传递数据
********************************************************************************/
// pipe.c
#include<stdio.h>
#include"apue.h"

int main()
{
	int n;
	int fd[2];
	pid_t pid;
	char line[MAXLINE];

	if (pipe(fd) < 0)
	{
		perror("pipe error");
	}
	if ((pid = fork()) < 0)
	{
		perror("fork error");
	}
	else if (pid > 0)
	{
		// parent
		close(fd[0]); // close the read pipe
		write(fd[1], "hello world
", 12);
	}
	else
	{
		// chlid
		close(fd[1]);  // close the write pipe
		n = read(fd[0], line, MAXLINE);
		write(STDOUT_FILENO, line, n);
	}

	exit(0);
}

 相反, 为了构造从子进程到父进程的管道, 则父进程关闭了写端fd[1], 子进程需关闭读端fd[0].

当管道的一端被关闭后, 有以下两条规则起作用:

  • 当读一个写端已被关闭的管道时,在所有数据都被读取后,read返回0, 以指示达到了文件的结束处.(从技术方面考虑,管道的写端还有进程时,就不会产生文件的结束.可以复制一个管道的描述符,使得有多个进程对他具有写打开文件描述符. 但是 ,通常一个管道只有一个读进程,一个写进程)
  • 如果写一个读端已被关闭的管道, 则产生信号SIGPIPE.如果忽略该信号或者捉该信号并从其处理程序返回,则write返回-1, error设置为EPIPE.

在写管道FIFO时,常量PIPE_BUF规定了内核中管道缓冲区的大小.如果对管道调用write,而且要求写的字节数小于等于PIPE_BUF,则此操作不会与其他进程对同一个管道的write操作穿插进行. 但是, 要是有多个进程同时写一个管道,而且有进程要求写的字节数超过PIPE_BUF字节时, 则写操作的数据可能会相互穿插. 用pathconf或者fpathconf函数可以确定PIPE_BUF的值.

 

原文地址:https://www.cnblogs.com/xiao13149920yanyan/p/3267497.html