概述
进程间通信,即InterProcess Communication,IPC。
管道
管道是UNIX系统最古老的IPC形式,但是管道具有以下两个局限性:
- 在历史上,管道是半双工的方式,即数据只能在一个方向上流动,当前一些操作系统的实现提供了全双工方式的管道;
- 管道只能在具有公共祖先的两个进程之间使用。
管道通过调用函数pipe创建的:
#include <unistd.h>
int pipe(int fd[2]);
/*若成功,返回0,若出错,返回-1*/
经由参数fd返回2个文件描述符,fd[0]为读而打开,fd[1]为写而打开,fd[1]的输出是fd[0]的输入。
对于在单个进程中设置管道是没有用处的,通过管道在不同进程之间传输数据。对于父进程与子进程,父进程先调用pipe,接着调用fork,从而创建父进程与子进程之间的IPC通道。
如果创建从父进程到子进程的管道,则父进程关闭管道的读端(fd[0]),子进程关闭管道的写端(fd[1])。如下图:
当一个管道的一端被关闭后:
- 当读(read)一个写端被关闭的管道时,在所有的数据被读取后,read返回0,表示文件结束(通常一个管道只有一个读进程和一个写进程)。
- 如果写(write)一个读端已经被关闭的管道时,会产生SIGPIPE信号,write返回-1,errno设置为EPIPE。
经过管道从父进程向子进程传送数据的范例为:
#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);
}
函数popen和pclose
标准提供了两个函数,实现创建一个连接到另一个进程的管道,然后读取其输出,或者向其输入发送数据。这两个函数的实现操作是:创建一个管道,fork一个子进程,关闭未使用的管道端,执行一个shell运行命令,然后等待命令终止。函数原型为:
#include <stdio.h>
FILE *popen(const char *cmdstring, const char *type);
/*若成功,返回文件指针,若出错,返回NULL*/
int pclose(FILE *fp);
/*若成功,返回cmdstring终止状态,若出错,返回-1*/