Linux IPC:管道符的实现
目录
- 一、了解管道符
- 二、实现管道符
本文主要了解如何模拟实现管道符,要使用的知识点:管道符、匿名管道、输出/输入重定向、程序替换。
一、了解管道符
管道符:|
管道符的作用可以结合下面的例子来了解一下:
- ps -ef | grep ./test
ps -ef:打印系统中的进程信息到标准输出。
grep ./test:搜索文件中包含./test的行并打印
管道符的作用就是将 ps -ef 中原本要打印到标准输出的信息转交给 grep ./test,然后grep程序就把这些信息中包含有./test的行打印出来。
二、实现管道符
来看看管道符的模拟实现流程:
因为我们使用的是匿名管道,因此首先要在父进程中创建匿名管道,然后才可以创建子进程,这样子进程就可以与父进程访问同一个匿名管道。
由于程序中涉及到两个程序:ps和grep,因此我们要创建两个子进程p1和p2。两个子进程的作用就是进行程序替换,一个运行ps程序,一个运行grep程序。
ps程序会把数据输出到标准输出,grep原本会从标准输出中接收数据并筛选,管道符将它们连接起来。
我们将子进程p1和p2进行程序替换后,两个进程之间无法直接传递数据,因此需要使用匿名管道来进行数据的传输。ps子进程将数据发送到匿名管道,grep子进程从匿名管道读取数据并筛选。因此两个子进程还需要进行输入输出重定向才可以实现上面的功能。
子进程p1:首先进行输出重定向,将原本要输出到标准输出的数据发送到匿名管道,然后进行程序替换运行ps程序。
子进程p2:首先进行输入重定向,将原本要从标准输入读取的数据改成从匿名管道读取,然后进行程序替换运行grep程序。
注意:ps程序在将数据发送到匿名管道后就会退出,但grep程序会一直等待,因为如果管道的写端没有全部关闭,管道的读端就不会退出。因此如果要想让grep程序打印完后退出,就要关闭所有写端(包括父进程的)。
为什么程序替换后,输入输出重定向依然有效?
因为程序替换更新的是虚拟地址空间,页表信息,但IO信息不会初始化。
如下是模拟实现管道符的代码:
#include<stdio.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
//使用匿名管道实现管道符
// ps -ef | grep realiz_pipe
int main(){
int pipefd[2];//输出参数
int ret = pipe(pipefd);//创建匿名管道
if(ret == -1){
printf("匿名管道创建失败\n");
return -1;
}
pid_t p1 = fork();//创建子进程p1运行ps
if(p1 == 0){
dup2(pipefd[1],1);//输出重定向
execlp("ps","ps","-ef",NULL);//进行程序替换
exit(-1);//替换失败才会运行到这里
}
pid_t p2 = fork();//创建子进程p2运行grep
if(p2 == 0){
close(pipefd[1]);//关闭写端,否则grep会一直等待
dup2(pipefd[0],0);//输入重定向
execlp("grep","grep","realiz_pipe",NULL);//进行程序替换
exit(-1);
}
close(pipefd[0]);
close(pipefd[1]);//所有写端都被关闭后,读端才会关闭
wait(NULL);//处理退出的子进程
wait(NULL);
}