管道
- 现在,某些系统提供全双工管道,但是为了最佳的可移植性,我们决不应预先假定系统支持全双工管道。
- 管道只能在具有公共祖先的两个进程之间使用。通常,一个管道由一个进程创建,在进程调用fork之后,这个管道就能在父进程和子进程之间使用了。
每当在管道中键入一个命令序列,让shell执行时,shell都会为每一条命令单独创建一个进程,然后用管道将前一条命令进程的标准输出与后一条命令的标准输入相连接
管道是通过调用pipe函数创建的。
#include <unistd.h>
int pipt(int fd[2]);
//返回值:若成功,返回0;若出错,返回-1
经由参数fd返回两个文件描述符:fd[0]为读而打开,fd[1]为写而打开。fd[1]的输出是fd[0]的输入。
对于从父进程到子进程的管道,父进程关闭管道的读端(fd[0]),子进程关闭管道的写端(fd[1])。
对于一个从子进程到父进程的管道,父进程关闭fd[1],子进程关闭fd[0]。
当管道的一段被关闭后,下列两条规则起作用。
1. 当读(read)一个写端已被关闭的管道时,在所有数据都被读取后,read返回0,表示文件结束。
2. 如果写(write)一个读端已被关闭的管道,则产生信号SIGPIPE。如果忽略该信号或者捕捉该信号并从其处理程序返回,则write返回-1,errno设置为EPIPE
常量PIPE_BUF规定了内核的管道缓冲区大小。
用pathconf或fpathconf函数可以确定PIPE_BUF的值。
#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){
close(fd[0]);
write(fd[1],"hello world\n",12);
}else{
close[fd[1]];
n = read(fd[0], line, MAXLINE);
write(STDOUT_FILENO, line, n);
}
exit(0);
}
函数popen和pclose
标准I/O库提供了两个函数popen和pclose。这两个函数实现的操作是:创建一个管道,fork一个子进程,关闭未使用的管道端,执行一个shell运行命令,然后等待命令终止
#include <stdio.h>
FILE *popen(const char *cmdstring, const char *type);
//返回值:若成功,返回文件指针;若出错,返回NULL
int pclose(FILE *fp);
//返回值:若成功,返回cmdstring的终止状态;若出错,返回-1
函数popen先执行fork,然后调用exec执行cmdstring,并且返回一个标准I/O文件指针。如果type是“r”,则文件指针连接到cmdstring的标准输出。
如果type是“w”,则文件指针连接到cmdstring的标准输入
pclose函数关闭标准I/O流。等待命令终止,然后返回shell的终止状态。如果shell不能被执行,则pclose返回的终止状态与shell已执行exit一样
协同进程
协同进程有连接到另一个进程的两个单项管道:一个接到其标准输入,另一个则来自其标准输出。