简体   繁体   中英

2 Pipe Problem, why does my parent process keep waiting?

I am trying to make a program containing 2 pipes, and in my program, the child will run first, the parent will run at the end. The result shows that Child 2, then Child1, and keep pending. It seems my parent is still waiting for some child process to be finished, but I only got 2 child process in this program~ Please help me:) Thanks!

#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/types.h>

int main(void)
{
    int pipefd[2];
    int pipefd2[2];
    int rv= pipe(pipefd);
    assert(rv > -1);
    int cid = fork();
    assert(cid > -1);
    int status;
    if( cid > 0 ){
        //waitpid(cid,NULL,0);
        printf("P %d %d\n",getpid(),getppid());
        wait(NULL);
        printf("Parent \n");
        close(0);
        dup(pipefd[0]);
        close(pipefd[0]);
        close(pipefd[1]);

        char *const wc_argv[] = {"wc", "-l", NULL};
        execvp("wc", wc_argv);
        //Parent - Redirect stdout to the write end of the pipe, and execute "ls -l"

    }else{
        int rv1= pipe(pipefd2);
        assert(rv1 > -1);
        int cid1 = fork();
        assert(cid1 > -1);

        if(cid1>0){
            printf("C1 %d %d\n",getpid(),getppid());
            wait(NULL);
            printf("Child1\n");
            //Child 1 (parent of child 2)
            close(0);
            dup(pipefd[0]);
            close(1);
            dup(pipefd2[1]);
            close(pipefd[0]);
            close(pipefd[1]);
            close(pipefd2[0]);
            close(pipefd2[1]);
            char *const grep_argv[] = {"grep", "D", NULL};
            execvp("grep", grep_argv);
        }else{
            printf("C2 %d %d\n",getpid(),getppid());
            printf("Child2\n");
            //Child 2 (child of child 1)
            close(1);
            dup(pipefd2[1]);
            close(pipefd2[0]);
            close(pipefd2[1]);
            close(pipefd[0]);
            close(pipefd[1]);
            char *const ls_argv[] = {"ls", "-l", NULL};
            execvp("ls", ls_argv);

        }

    }
}

There are multiple issues with your code. I pointed out some minor matters in comments, but the ones mainly likely to be responsible for the misbehavior you describe are:

  • Child 1 and the parent both redirect pipefd[0] to their standard inputs. Probably you want child 1 to redirect pipefd2[0] to its standard input instead, but you definitely don't want the two to have the same standard input.

  • Child 1 redirects its standard output to pipefd2[1] , the other end of which pipe will be its standard input once you correct the previous issue. You appear to instead want to redirect to pipefd[1] , which presently is not served at all.

  • Child 1 waits for child 2 before it proceeds. This is non-idiomatic and risky, for you will get a deadlock if child 2 fills the buffer of the second pipe, and therefore blocks before terminating. Pipes are data conduits. Although they do have internal buffers, this should be regarded as an implementation detail. It is incorrect to rely on pipes for buffering. The correct model is that data is consumed from the pipe's read end concurrently with data being written to the pipe's write end.

  • The parent waits for child 1 before it proceeds. As with child 1's wait, this is risky and non-idiomatic.

Additionally, as @IanAbott remarked in comments, with the way you are arranging the pipes, child 1 waiting for child 2 will reliably produce deadlock. The latter execs a program that will read its standard input to the end, but it will not see EOF on its input until the other ends of the pipe is closed, and that is never closed because child 1 waits on child 2 to finish before it proceeds. I see no necessity for the waits -- neither child 1's nor the parent's -- they could and should just be removed.

OMG., Thanks ALL This is my first time posting a question in stack overflow. I cant believe you guys are so helpful, thank you so much and i have solved my problem right now. I can believe I just made a really simple mistake, which is in Child1

        close(0);
        dup(pipefd2[0]);
        close(1);
        dup(pipefd[1]);

Original, my program will run parent first, then i want to modify it, then i just thought exchanging the child 2 and parent, everything will be fine, but i forgot to modify the content of child1. Anyways, you guys are so helpful, and hope you guys stay safe and keep going on our it adventure:)

BTW, I can see there are a lot of recommendations for my code, I will try to digest it:). Thanks all again!!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM