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);
}

猜你喜欢

转载自blog.csdn.net/weixin_57761086/article/details/128525224
今日推荐