即使关闭Write结束也会读取阻塞

时间:2014-10-25 14:39:14

标签: c linux pipe fork system-calls

int  main()
{


    int p[2];
    int p1[2];
    pipe(p);
    pipe(p1);

    int pid,status;

    char buff[10000];

    pid = fork();

    if(pid == 0)
    { 
        close(p[0]);
        dup2(p[1],1);
        close(p[1]);

        char *argv[] = {"ls","-l",NULL};
        execv("/bin/ls",argv);
    }
    else
    {
        wait(&status);
        pid =fork();
        if (pid ==0)
        {
            close(p[1]);
            dup2(p[0],0);
            close(p[0]);

            close(p1[0]);
            dup2(p1[1],1);
            close(p1[1]);

            char *argv[] = {"uniq",NULL};

            execv("/bin/uniq",argv);
        }
        else
        {
            wait(&status);

            close(p1[1]);
            dup2(p1[0],0);
            close(p1[0]);

            char *argv[] = {"grep","^d",NULL};
            execv("/bin/grep",argv);
        }
    }
}

为什么读取是在子进程中阻塞(uniq进程),即使我已正确关闭了端点(假设我已经关闭)。尝试过strace并且持续打3到4小时。我想知道它为什么阻止......任何帮助都会有所帮助:)

1 个答案:

答案 0 :(得分:1)

问题是您没有关闭所有未使用的管道文件描述符。例如,在您exec("/bin/grep", argv)的最后一个分支中,您关闭了p1[1]dup2() p1[0],但您并未关闭{{1} }或p[0]。因此,当p[1]写完ls时,该管道保持打开状态,因为您仍然有悬空引用它。

您还没有检查任何系统调用是否存在错误,您应该这样做。

以下是修订版(略有修改,因为uniqgrep位于我系统的不同位置):

uniq

并输出:

#define _POSIX_C_SOURCE 200809L

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    int p1to2[2];
    int p2to3[2];

    if ( pipe(p1to2) == -1 || pipe(p2to3) == -1 ) {
        perror("error calling pipe()");
        return EXIT_FAILURE;
    }

    pid_t pid;

    if ( (pid = fork()) == -1 ) {
        perror("error calling first fork()");
        return EXIT_FAILURE;
    }
    else if (pid == 0) {
        if ( close(p1to2[0]) == -1 ) {
            perror("error calling close() on p1to2[0]");
            return EXIT_FAILURE;
        }
        if ( p1to2[1] != STDOUT_FILENO ) {
            if ( dup2(p1to2[1], STDOUT_FILENO) == -1 ) {
                perror("error calling dup2() on p1to2[1]");
                return EXIT_FAILURE;
            }
            if ( close(p1to2[1]) == -1 ) {
                perror("error calling close() on p1to2[1]");
                return EXIT_FAILURE;
            }
        }

        if ( close(p2to3[0]) == -1 || close(p2to3[1]) == -1 ) {
            perror("error calling close() on p2to3");
            return EXIT_FAILURE;
        }

        char *argv[] = {"ls", "-l", NULL};

        if ( execv("/bin/ls", argv) == -1 ) {
            perror("couldn't execute /bin/ls");
            return EXIT_FAILURE;
        }
    } else {
        if ( (pid = fork()) == -1 ) {
            perror("error calling second fork()");
            return EXIT_FAILURE;
        }
        else if ( pid == 0 ) {
            if ( close(p1to2[1]) == -1 ) {
                perror("error calling close() on p1to2[1]");
                return EXIT_FAILURE;
            }
            if ( p1to2[0] != STDIN_FILENO ) {
                if ( dup2(p1to2[0], STDIN_FILENO) == -1 ) {
                    perror("error calling dup2() on p1to2[0]");
                    return EXIT_FAILURE;
                }
                if ( close(p1to2[0]) == -1 ) {
                    perror("error calling close() on p1to2[0]");
                    return EXIT_FAILURE;
                }
            }

            if ( close(p2to3[0]) == -1 ) {
                perror("error calling close() on p2to3[0]");
                return EXIT_FAILURE;
            }
            if ( p2to3[1] != STDOUT_FILENO ) {
                if ( dup2(p2to3[1], STDOUT_FILENO) == -1 ) {
                    perror("error calling dup2() on p2to3[1]");
                    return EXIT_FAILURE;
                }
                if ( close(p2to3[1]) == -1 ) {
                    perror("error calling close() on p2to3[1]");
                    return EXIT_FAILURE;
                }
            }

            char *argv[] = {"uniq", NULL};

            if ( execv("/usr/bin/uniq", argv) == -1 ) {
                perror("couldn't execute /usr/bin/uniq");
                return EXIT_FAILURE;
            }
        } else {
            if ( close(p1to2[0]) == -1 || close(p1to2[1]) == -1 ) {
                perror("error calling close() on p1to2");
                return EXIT_FAILURE;
            }

            if ( close(p2to3[1]) == -1 ){
                perror("error calling close() on p2to3[1]");
                return EXIT_FAILURE;
            }
            if ( p2to3[0] != STDIN_FILENO ) {
                if ( dup2(p2to3[0], STDIN_FILENO) == -1 ) {
                    perror("error calling dup2() on p2to3[0]");
                    return EXIT_FAILURE;
                }
                if ( close(p2to3[0]) == -1 ) {
                    perror("error calling close() on p2to3[0]");
                    return EXIT_FAILURE;
                }
            }

            char *argv[] = {"grep", "pipes", NULL};

            if ( execv("/usr/bin/grep", argv) == -1 ) {
                perror("couldn't execute /usr/bin/grep");
                return EXIT_FAILURE;
            }
        }
    }
}

顺便提一下,当您有多个管道paul@horus:~/src/sandbox$ ./pipes -rwxr-xr-x 1 paul staff 8812 Oct 25 12:21 pipes -rw-r--r-- 1 paul staff 3817 Oct 25 12:21 pipes.c -rw------- 1 paul staff 660 Oct 25 11:03 pipes.c.BAK paul@horus:~/src/sandbox$ close()以及dup2()p等变量时,很容易感到困惑,特别是当您添加需要的错误检查时。这是一个很好的例子,将程序组合成函数可以极大地帮助,并避免因为很难弄清楚正在发生什么而引入错误。

以下是建议的构成,我建议p1功能在此处更容易理解,推理和排除故障:

main()