学习管道,EXEC,叉,并试图链三个过程在一起 [英] Learning pipes, exec, fork, and trying to chain three processes together

查看:141
本文介绍了学习管道,EXEC,叉,并试图链三个过程在一起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我学习使用管道和的管道的。该方案使得使用叉子两个子进程。第一个孩子跑'ls'的命令,并输出到PIPE1。第二个从PIPE1运行'WC',输出到标准输出读取。

我只是想在从PIPE1和输出pipe2读取中间添加第三个过程。基本上我想要做的。

  LS |猫|厕所-l

我想要做的:

 (LS)标准输出 - > PIPE1  - >标准输入(CAT)stdout->标准输入(WC -l) -  GT;标准输出

没有什么是打印到stdout和程序永远不会退出。

下面是我的code的变化过程#3

  INT
主(INT ARGC,CHAR *的argv [])
{
    INT PFD [2]; / *管道文件描述符* /
    INT PFD2 [2];    如果(管(PFD)== -1)/ *创建管道* /
        PERROR(管子);    如果(管(PFD2)== -1)/ *创建管道* /
        PERROR(管子);    / *
    叉流程1和exec ls命令
    写入功率通量密度[1],靠近PFD [0]
    * /
    开关(叉())​​{
    情况1:
        PERROR(叉);    情况下0:
        如果(接近(PFD [0])== - 1)
            PERROR(关闭1);        //在PFD DUP标准输出[1]
        如果(PFD [1]!= STDOUT_FILENO){
            如果(dup2(PFD [1],STDOUT_FILENO)== - 1)
                PERROR(dup2 2);
            如果(接近(PFD [1])== - 1)
                PERROR(接近4);
        }
        execlp(LS,LS,(字符*)NULL);
        PERROR(execlp LS);
    默认:
        打破;
    }    / *
    *叉过程2和exec wc命令
    从PFD阅读[0],靠近PFD [1]
    写入PFD [1],靠近PFD2 [0]
    * /
    开关(叉())​​{
    情况1:
        PERROR(叉);
    情况下0:
        //从PFD阅读[0]
        如果(接近(PFD [1])== - 1)
            PERROR(关闭3);        如果(PFD [0]!= STDIN_FILENO){
            如果(dup2(PFD [0],STDIN_FILENO)== - 1)
                PERROR(dup2 2);
            如果(接近(PFD [0])== - 1)
                PERROR(接近4);
        }        如果(PFD2 [1]!= STDOUT_FILENO){
            如果(dup2(PFD2 [1],STDOUT_FILENO)== - 1)
                PERROR(dup2 2);
            如果(接近(PFD2 [1])== - 1)
                PERROR(接近4);
        }        execlp(猫,猫,(字符*)NULL);
        PERROR(execlp猫);
    默认:
        打破;
    }    / *
    *叉过程3
    * /
    开关(叉())​​{
    情况1:
        PERROR(叉);
    情况下0:
        如果(接近(PFD2 [1])== - 1)
            PERROR(关闭3);        如果(PFD2 [0]!= STDIN_FILENO){
            如果(dup2(PFD2 [0],STDIN_FILENO)== - 1)
                PERROR(dup2 2);
            如果(接近(PFD2 [0])== - 1)
                PERROR(接近4);
        }        execlp(WC,WC,-l(字符*)NULL);
        PERROR(execlp WC);
    默认:
        打破;
    }
    / *父进程关闭管道未使用的文件描述符,并等待孩子* /    如果(接近(PFD [0])== - 1)
        PERROR(接近5);
    如果(接近(PFD [1])== - 1)
        PERROR(接近6);
    如果(接近(PFD2 [0])== - 1)
        PERROR(接近5);
    如果(接近(PFD2 [1])== - 1)
        PERROR(接近6);    如果(等待(NULL)== -1)
        PERROR(等待1);
    如果(等待(NULL)== -1)
        PERROR(等待2);
    如果(等待(NULL)== -1)
        PERROR(等待3);    出口(EXIT_SUCCESS);
}


解决方案

的问题是,你没有关闭 PFD [1] 过程3,加入关闭(PFD [1]); 在这个过程中的情况下0后3将修复它。

在过程3,即读PFD [0] ,但是有四个 PFD [1] 在这些过程:


  1. 进程0

    这是主要的过程中, PFD [1] 在这个过程中会通过收盘前关闭等待()


  2. 1的过程

    LS 完成后, PFD [1] 在这个过程中会自动被操作系统关闭。


  3. 2的过程

    PFD [1] 执行之前已关闭


  4. 3的过程

    PFD [1] 是在这个过程中,而厕所运行打开了,这是发生了什么事时刻:


    1. 在过程2,试图读取 PFD [0] 数据PFD [1]

    2. 在过程3,厕所试图读取 PFD2 [0] 数据PFD2 [1]

    3. ,因为 PDF [1] 仍然打开过程3,什么都不会被写入到它,从 PFD阅读[0] 过程2(cat)将会永远等待

    4. ,因为过程3还活着,从 PFD2过程3(WC)[0] 读书会等待(永远)


正如你所看到的,你必须处理2(猫)之间的过程,因为文件描述符泄漏的僵局3(WC)。为了打破这一僵局,你只需要关闭 PFD [1] 过程3运行厕所,之后前


  1. 过程2 过程1退出LS 后会退出,因为没有留给它(猫)读

  2. 过程2个出口,厕所过程3也将退出,因为没有留下它(WC)读

  3. 之后,主进程(父进程)将退出,并计划将完成。


有可能有多于一个写为一管道的读结束时结束,除非所有这些写端部是封闭的,文件结束-不会被传递到读端,并且读取器将只是等待更多的数据来。如果没有要到了,读者会永远等待。

I'm learning to use pipes and following along with this code on pipes. The program makes two child processes using fork. The first child runs 'ls' command and outputs to pipe1. The second reads from pipe1 runs 'wc' and outputs to stdout.

I'm just trying to add a third process in the middle that reads from pipe1 and outputs to pipe2. Basically what I'm trying to do

  ls | cat | wc -l

What I'm trying to do:

(ls)stdout -> pipe1 -> stdin(cat)stdout-> stdin(wc -l) -> stdout

Nothing ever prints to stdout and the program never exits.

Here's my code with the changes for process #3

int
main(int argc, char *argv[])
{
    int pfd[2];                                     /* Pipe file descriptors */
    int pfd2[2];

    if (pipe(pfd) == -1)                            /* Create pipe */
        perror("pipe");

    if (pipe(pfd2) == -1)                            /* Create pipe */
        perror("pipe");

    /*
    Fork process 1 and exec ls command
    write to pfd[1], close pfd[0]
    */
    switch (fork()) {
    case -1:
        perror("fork");

    case 0:             
        if (close(pfd[0]) == -1)                   
            perror("close 1");

        // dup stdout on pfd[1]
        if (pfd[1] != STDOUT_FILENO) {            
            if (dup2(pfd[1], STDOUT_FILENO) == -1)
                perror("dup2 2");
            if (close(pfd[1]) == -1)
                perror("close 4");
        }
        execlp("ls", "ls", (char *) NULL);          
        perror("execlp ls");
    default:            
        break;
    }

    /*
    *   Fork process 2 and exec wc command
    read from pfd[0], close pfd[1]
    write to pfd[1], close pfd2[0]
    */
    switch (fork()) {
    case -1:
        perror("fork");
    case 0:  
        // read from pfd[0]           
        if (close(pfd[1]) == -1)                  
            perror("close 3");

        if (pfd[0] != STDIN_FILENO) {            
            if (dup2(pfd[0], STDIN_FILENO) == -1)
                perror("dup2 2");
            if (close(pfd[0]) == -1)
                perror("close 4");
        }

        if (pfd2[1] != STDOUT_FILENO) {            
            if (dup2(pfd2[1], STDOUT_FILENO) == -1)
                perror("dup2 2");
            if (close(pfd2[1]) == -1)
                perror("close 4");
        }

        execlp("cat", "cat", (char *) NULL);
        perror("execlp cat");
    default:
        break;
    }

    /*
    *   Fork process 3
    */
    switch (fork()) {
    case -1:
        perror("fork");
    case 0:          
        if (close(pfd2[1]) == -1)                  
            perror("close 3");

        if (pfd2[0] != STDIN_FILENO) {            
            if (dup2(pfd2[0], STDIN_FILENO) == -1)
                perror("dup2 2");
            if (close(pfd2[0]) == -1)
                perror("close 4");
        }

        execlp("wc", "wc", "-l", (char *) NULL);
        perror("execlp wc");
    default:
        break;
    }


    /* Parent closes unused file descriptors for pipe, and waits for children */

    if (close(pfd[0]) == -1)
        perror("close 5");
    if (close(pfd[1]) == -1)
        perror("close 6");
    if (close(pfd2[0]) == -1)
        perror("close 5");
    if (close(pfd2[1]) == -1)
        perror("close 6");

    if (wait(NULL) == -1)
        perror("wait 1");
    if (wait(NULL) == -1)
        perror("wait 2");
    if (wait(NULL) == -1)
        perror("wait 3");

    exit(EXIT_SUCCESS);
}

解决方案

The problem is that you did not close pfd[1] in process 3, add close(pfd[1]); after case 0 in that process 3 will fix it.

In process 3, that cat will read from pfd[0], however there are four pfd[1] in those processes:

  1. process 0

    this is the main process, pfd[1] in this process will be closed by that close before wait().

  2. process 1

    after ls finished, pfd[1] in this process will be closed automatically by the operating system.

  3. process 2

    pfd[1] has been closed before executing cat.

  4. process 3

    pfd[1] is open in this process while wc is running, and this is what happened at that moment:

    1. in process 2, cat tries to read pfd[0] for data from pfd[1]
    2. in process 3, wc tries to read pfd2[0] for data from pfd2[1]
    3. because pdf[1] still open in process 3, and nothing will be written to it, reading from pfd[0] in process 2 (cat) will wait forever
    4. because cat in process 3 still alive, reading from pfd2[0] in process 3 (wc) will wait (forever)

As you can see, you have a deadlock between process 2 (cat) and process 3 (wc) because of file descriptor leak. To break this deadlock, you just need to close pfd[1] in process 3 before you run wc, after that:

  1. cat in process 2 will exit after ls in process 1 exits, because there is nothing left for it (cat) to read
  2. after cat in process 2 exits, wc in process 3 will also exit, because there is nothing left for it (wc) to read
  3. after that, the main process (parent process) will exit, and the program will finish.


It is possible that there are more than one write ends for the read end of a pipe, unless all these write ends are closed, end-of-file will not be delivered to the read end, and the reader will just wait for more data to come. If there is nothing to come, that reader will wait forever.

这篇关于学习管道,EXEC,叉,并试图链三个过程在一起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆