4

I'm trying to implement this using pipe() and fork() :

ls | wc

First I checked if pipe works fine, and here is the code.

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

int main(void){

    char *param1[]={"ls",NULL};
    char *param2[]={"wc",NULL};

    int p[2];
    pipe(p);

    pid_t process1, process2;

    if((process1=fork())==0){ // child 1
        dup2(p[1],1); // redirect stdout to pipe
        close(p[0]);
        execvp("ls", param1);
        perror("execvp ls failed");
    }
    else if(process1>0){ // parent
        wait(NULL);
    }

    if((process2=fork())==0){ // child 2
        dup2(p[0],0); // get stdin from pipe
        close(p[1]);

        char buff[1000]={0};
        read(STDIN_FILENO,buff,250);
        printf("---- in process2 -----\n%s\n",buff);
    }
    else if(process2>0){ // parent
        wait(NULL);
    }
    return 0;
}

I checked it works fine. I replaced read() and printf() to exec(), like :

if((process2=fork())==0){ // child 2
    dup2(p[0],0); // get stdin from pipe
    close(p[1]);

    execvp("wc",param2);
    perror("execvp wc failed");
}

My terminal just hang. I think wc process doesn't get any input. So my question is, why read() and printf() works, and execvp() doesn't work?

wanttobepro
  • 43
  • 1
  • 5
  • What is the question here ? – asio_guy Dec 12 '17 at 08:21
  • You have no error handling if the first process failed to start! Additionally, have you tried waiting for the processes after *both* of them executed (prevents the pipe running full)? – Aconcagua Dec 12 '17 at 08:31
  • @potato I fixed my question, thanks – wanttobepro Dec 12 '17 at 08:31
  • Just a recommendation: if you use `STDIN_FILENO` for `read`, just use these macros, too, for `dup2`... And why do you provide a buffer of size 1000 if you only use 250 bytes anyway? Would rather select buffer sizes in powers of two (1024, 256, ...). – Aconcagua Dec 12 '17 at 08:35
  • @Aconcagua No I haven't. thanks. And I just wanted to check my simple pipe working, regardless of size. – wanttobepro Dec 12 '17 at 08:39
  • here is a similar question possibly a duplicate https://stackoverflow.com/questions/13801175/classic-c-using-pipes-in-execvp-function-stdin-and-stdout-redirection – asio_guy Dec 12 '17 at 08:41
  • 1
    Possible duplicate of [Classic C. Using pipes in execvp function, stdin and stdout redirection](https://stackoverflow.com/questions/13801175/classic-c-using-pipes-in-execvp-function-stdin-and-stdout-redirection) – asio_guy Dec 12 '17 at 08:42
  • By the way, you should check the return value of [`pipe`](http://man7.org/linux/man-pages/man2/pipe.2.html), too... – Aconcagua Dec 12 '17 at 08:52

1 Answers1

1

You need not to wait every time you create a new process and also close the descriptor in the parent, something like:

if((process1=fork())==0){ // child 1
    dup2(p[1],1); // redirect stdout to pipe
    close(p[0]);
    execvp("ls", param1);
    perror("execvp ls failed");
}
else if(process1==-1){ // fork failed
    exit(1);
}
close(p[1]); // no need for writing in the parent

if((process2=fork())==0){ // child 2
    dup2(p[0],0); // get stdin from pipe

    char buff[1000]={0};
    read(STDIN_FILENO,buff,250);
    printf("---- in process2 -----\n%s\n",buff);
}
else if(process2==-1){ // second fork failed
    close(p[0]); // ensure there is no reader to the pipe
    wait(NULL); // wait for first chidren
    exit(1);
}
close(p[0]); // no need for reading in the parent

wait(NULL);
wait(NULL); // wait for the two children
Aconcagua
  • 24,880
  • 4
  • 34
  • 59
Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
  • Thanks, It works. I have a question : is `close()` necessary? I can check if I didn't use `close()`, it doesn't work – wanttobepro Dec 12 '17 at 08:58
  • 1
    @wanttobepro `close()` is necessary on the input to `wc` because that is how it knows to stop counting words. – JeremyP Dec 12 '17 at 09:33
  • @wanttobepro As Jeremy says closing in the parent is a necessity, pipe semantic is to provide synchronization between ends, so if you don't close it may happen that a children think that there is somebody else on the other end of the pipe. – Jean-Baptiste Yunès Dec 12 '17 at 09:39