Search code examples
clinuxubuntupipesystems-programming

Why does my C program of a pipeline with two pipes hang?


I am trying to write a C program that does something like the pipeline ls | wc | wc. I already did it for ls | wc, and it worked fine, but I can't figure out why my program stops at the child process in the indicated line.

int main (void)
{
    pid_t pid_fils, pid_pfils;

    int fd[2], fd2[2];

    if(pipe(fd)==-1 || pipe(fd2)==-1)
    {
        printf("pipe failed!");
        return 1;
    }

    printf("program started\n");
    pid_fils=fork();
    if(pid_fils==0)
    {
        pid_pfils=fork();
        if(pid_pfils==0)
        {
            //action3
            printf("I am the grandson\n");
            close(fd[0]);//close read side
            dup2(fd[1],1);//connect write with stdout
            close(fd[1]);//close write side
            execlp("ls","ls",(char*)0);
            //execvp("ls",argv3);
            return 0;/*actions grandson*/
        }
        else
        {
            //action2
            printf("I am the son\n");
            wait();
            printf("son, wait ok\n");
            >close(fd[1]);  //close read side
            >dup2(fd[0],0); //connect write with stdin
            >close(fd[0]);  //close read side
            
            ///////pipe2////
           > close(fd2[0]);  //close read side
            >dup2(fd2[1],1); //connect write with stdout/*it stops here -can't display "ok!"*/
            printf("ok!\n");    
            >close(fd2[1]);  //close write side

            execlp("wc","wc",(char*)0);
            printf("error exec returned!\n");    
            return 0;
        }
    }
    else
    {
        ///action1
        printf("I am the parent\n");
        wait();
        printf("parent,wait ok\n");
        close(fd2[1]);  //close write side, 
        dup2(fd2[0],0); //connect read with stdin
        close(fd2[0]);  //close read side
        execlp("wc","wc",(char*)0);
        return 0;/*the parent*/
    }
    return 1;
}

Solution

  • Make sure you close all unused descriptors. In your case, the easiest solution is to move the creation of pipe(fd) into the first if block (in the first sub-process). The problem is that as long as any process could possibly write to the pipe, the reader won't get EOF and so won't terminate.

    if(pipe(fd2)==-1)
    {
        printf("pipe failed!");
        return 1;
    }
    
    printf("program started\n");
    pid_fils=fork();
    if(pid_fils==0)
    {
        if(pipe(fd)==-1)
        {
            printf("pipe failed!");
            return 1;
        }
        pid_pfils=fork();
    

    I should also mention that you may want to reconsider the wait calls. Not sure what you are intending to do with them but you don't want the "ls" process to block on output because the reader hasn't been started yet.