1. 前言
进程间通信(InterProcess Communication, IPC)方式包括:管道
、FIFO、消息队列、信号量以及共享存储。
本篇学习笔记只记录管道通信。
2. 管道介绍
2.1 管道原理
管道是UNIX系统IPC的最古老形式,所有UNIX系统都提供此种通信机制。管道有两种局限性:
半双工
的,即数据只能在一个方向上流动。现在有些系统支持全双工管道。- 管道只能在具有
公共祖先
的两个进程之间使用。通常,一个管道由一个进程创建,在进程调用fork之后,这个管道就能在父进程和子进程之间使用了。
每当在管道中键入一个命令序列,让shell执行,shell都会为每一条命令单独创建一个进程,然后用管道将前一条命令进程的标准输出与后一条命令的标准输入相连接。
个人理解:经常用的命令ps -ef | grep 66750
查看进程信息,shell做的工作如下:
- 给
ps -ef
命令创建一个进程 - 给
grep 66750
命令创建一个进程 - 用管道将ps -ef 的输出连接到grep 66750的输入,所以这儿的管道是shell创建的。
ps -ef
命令的输出会被保存到内存里。
从下图可以看出两个子进程ps -ef
和grep 66750
被创建出来了,并且是相同的父进程bash
。
管道是通过调用pipe函数创建的:
#include <unistd.h>
int pipe(int fd[2]);
返回值:若成功,返回0, 若出错,返回-1。
参数fd为两个文件描述符,f[0]为读而打开,fd[1]为写而打开。fd[1]的输出是fd[0]的输入。
2.2 管道例子
2.2.1 例子1,创建一个从父进程到子进程的管道,并且父进程经由该管道向子进程传送数据。
#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){ /* 父进程 */
// 关闭父进程的读文件描述符
printf("parent pid: %d\n", pid);
close(fd[0]);
write(fd[1], "hello world\n", 12);
printf("parent write finish!\n");
} else { /* pid == 0为子进程 */
// 关闭子进程的写文件描述符
printf("chaild pid: %d\n", pid);
close(fd[1]);
// 从读文件描述符里获取内容
n = read(fd[0], line, MAXLINE);
// 写到标准输出里
write(STDOUT_FILENO, line, n);
printf("child read finish and show to stdout!\n");
}
exit(0);
}
2.2.2 例子2,每次一页地显示已产生的输出,将文件复制到分页程序
原理可分如下几步:
1) 父进程创建管道
2)父进程把文件读取出来写入到文件描述符fd[1]中
3)子进程调用execl()函数,该函数会调用分页程序/bin/more
,将管道中的内容输出出来。
代码参考:将文件复制到分页程序
运行效果:
成功将文件/tmp/test/test.c内容输出出来了
3. 参考资料
3.1 《UNIX环境高级编程第3版》 P430-P435
3.2 Linux 的进程间通信:管道 https://zhuanlan.zhihu.com/p/58489873
3.3 Unix环境高级编程——解决第一个问题“apue.h: No such file or directory” : https://blog.csdn.net/qq_41899773/article/details/107376991