Thread: Communication through pipes

  1. #16
    C Beginner
    Join Date
    Dec 2011
    Location
    Portugal
    Posts
    187
    Quote Originally Posted by smokeyangel View Post
    Code:
        if(pipe(fd)==-1){perror("demo");exit(1);}
        if ((pid = fork()) == -1)   {perror("demo"); exit(1);}
        else
            waitpid(-1, &status, 0);
        
        if(pid==0) // filho
        {
            dup2(fd[1],1);

    That doesn't look right. Assuming the fork() succeeds, then the child will have pid 0 and the parent will have its pid. So having done the fork, both the parent and the child will go to waitpid() because neither pid is -1.


    You need to sort out your types and make sure you're not passing garbage pointers all over the place.
    Code:
     int *status; // this is an uninitialised int pointer. 
     char* buffer; // again uninitialised pointer, trying to write to this could crash your program or cause weird behaviour
     char buffer[1000]; // this has statically allocated 1000 bytes of space. So you can actually write to this
     int status2;  // Just an int. You can use &status to pass the address where an int* is required, and just read it as a normal int here.

    If you pass status to waitpid correctly you can check it and find out why it didn't stop.

    I've sorted my types out, thanks.


    Hmm, so having the child pid 0 where should I have my waitpid ?


    I need it to enter the son first :
    Code:
    if(pid==0) // filho
        {
            dup2(fd[1],1);
            printf("filho\n");
            // printf("o arg é %s",arg);
            int a = execlp(cmd,cmd,arg,NULL); //o comando é o primeiro argumento da main e o argumento é a linha/ficheiro...
            //  printf("ja acabou - %d\n",a);
            perror("demo");
            //_exit(pid); //filho morra
        }

    But instead it's joining the parent process :


    Code:
    else{
            printf("pai\n");
            while((d=read(1,buffer,1000))>0) {
                printf("ola");
                buffer[d] = '\0';
                printf("<<<<%s\n",buffer);
            }

    This is the last thing I need done in my work and I'm not being able to sort it out :/

    I think it's -1 also since this is the meaning of it :

    If pid is equal to -1, the calling process waits for any child process to terminate.


    Please help guys
    Last edited by DeanWinchester; 06-01-2013 at 12:38 PM.

  2. #17
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,666
    Did you change it to

    int status;

    ///

    waitpid( -1, &status, 0 );



    Because simply changing it to waitpid(-1, status, 0); would make the compiler shut up (hey, I wanted an int pointer, and this is one), but it doesn't make it right.

    Each and every one of your * variables needs careful analysis to make sure it's both necessary and pointing at some valid memory.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #18
    C Beginner
    Join Date
    Dec 2011
    Location
    Portugal
    Posts
    187
    Quote Originally Posted by Salem View Post
    Did you change it to

    int status;

    ///

    waitpid( -1, &status, 0 );



    Because simply changing it to waitpid(-1, status, 0); would make the compiler shut up (hey, I wanted an int pointer, and this is one), but it doesn't make it right.

    Each and every one of your * variables needs careful analysis to make sure it's both necessary and pointing at some valid memory.
    Yes, I did change it to that and still it ain't working.
    I completely have no idea why he just doesn't enter the son part instead of the dad part .. :/

  4. #19
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    From the fork(2): create child process - Linux man page docs:

    Return value: On success, the PID of the child process is returned in the parent, and 0 is returned in the child. On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately.
    So the value of the "pid" variable is 0 in the child, and > 0 in the parent.

    I think it's -1 also since this is the meaning of it :

    If pid is equal to -1, the calling process waits for any child process to terminate.
    Yes, that's from the waitpid(2): wait for process to change state - Linux man page page. It's just a special value meaning "any child". Your waitpid function looks ok.

    I think it should be:
    Code:
     pid = fork();
    
     if (pid == -1)
        /// error
     else if (pid == 0) 
        //execlp
      else
        // parent stuff
        waitpid()
    Just so long as you move the fork() call outside of that if condition, I think it's probably fine otherwise.

    What makes you think that the child is going to the parent process? Is it printing "pai" twice?
    If it's just printing it once, I think it might be because of this:

    Code:
    if(pid==0) // filho
        {
            dup2(fd[1],1);
            printf("filho\n");
    I think that dup2 has replaced the child's stdout with the pipe. You could fprintf to stderr instead to see if anything comes up.

    Code:
    while((d=read(1,buffer,1000))>0) {
    And there you're trying to read from stdout?

  5. #20
    C Beginner
    Join Date
    Dec 2011
    Location
    Portugal
    Posts
    187
    Quote Originally Posted by smokeyangel View Post
    From the fork(2): create child process - Linux man page docs:



    So the value of the "pid" variable is 0 in the child, and > 0 in the parent.



    Yes, that's from the waitpid(2): wait for process to change state - Linux man page page. It's just a special value meaning "any child". Your waitpid function looks ok.

    I think it should be:
    Code:
     pid = fork();
    
     if (pid == -1)
        /// error
     else if (pid == 0) 
        //execlp
      else
        // parent stuff
        waitpid()
    Just so long as you move the fork() call outside of that if condition, I think it's probably fine otherwise.

    What makes you think that the child is going to the parent process? Is it printing "pai" twice?
    If it's just printing it once, I think it might be because of this:

    Code:
    if(pid==0) // filho
        {
            dup2(fd[1],1);
            printf("filho\n");
    I think that dup2 has replaced the child's stdout with the pipe. You could fprintf to stderr instead to see if anything comes up.

    Code:
    while((d=read(1,buffer,1000))>0) {
    And there you're trying to read from stdout?
    I don't think the child is going to the father process.
    What I think and know is my program isn't entering here :
    Code:
    else if (pid==0)
        {
            dup2(fd[1],1);
            printf("son\n");
            int a = execlp(cmd,cmd,arg,NULL);
            perror("demo");
        }
    With :
    Code:
    while((d=read(1,buffer,1000))>0) {
    I'm trying to read what the son has wrote using dup2(fd[1],1)


  6. #21
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    Quote Originally Posted by DeanWinchester View Post
    What I think and know is my program isn't entering here :
    Code:
    else if (pid==0)
        {
            dup2(fd[1],1);
            printf("son\n");
            int a = execlp(cmd,cmd,arg,NULL);
            perror("demo");
        }
    Ok. Perhaps pid is getting corrupted somehow. What does your whole function look like now?

    Can you add some fprintfs to check the value of pid after the fork and before the dup2? You should see the parent and child's pids, so should be able to see if the child pid isn't 0.

    Code:
    fprintf(STDERR, "\npid: %d", pid);
    else if (pid==0)
        {
            fprintf(STDERR, "\npid: %d", pid);
            dup2(fd[1],1);
            printf("son\n");

    Code:
    while((d=read(1,buffer,1000))>0) {
    I'm trying to read what the son has wrote using dup2(fd[1],1)
    Ah. That's not right. pipe(2): create pipe - Linux man page
    Quote Originally Posted by pipe docs
    pipe() creates a pipe, a unidirectional data channel that can be used for interprocess communication. The array pipefd is used to return two file descriptors referring to the ends of the pipe. pipefd[0] refers to the read end of the pipe. pipefd[1] refers to the write end of the pipe. Data written to the write end of the pipe is buffered by the kernel until it is read from the read end of the pipe.
    So the all the child's standard output will go to the pipe, To read it you need to read from fd[0].

  7. #22
    C Beginner
    Join Date
    Dec 2011
    Location
    Portugal
    Posts
    187
    Quote Originally Posted by smokeyangel View Post
    Ok. Perhaps pid is getting corrupted somehow. What does your whole function look like now?

    Can you add some fprintfs to check the value of pid after the fork and before the dup2? You should see the parent and child's pids, so should be able to see if the child pid isn't 0.

    Code:
    fprintf(STDERR, "\npid: %d", pid);
    else if (pid==0)
        {
            fprintf(STDERR, "\npid: %d", pid);
            dup2(fd[1],1);
            printf("son\n");



    Ah. That's not right. pipe(2): create pipe - Linux man page


    So the all the child's standard output will go to the pipe, To read it you need to read from fd[0].
    My whole function right now looks like this :

    Code:
    void map(char* cmd, char* arg){
        int i;
        int d=0;
        int pid = fork();
        FILE *stream;
        int status;
        char buffer[1000];
        stream = fopen("merdas.txt","a");
        int fd[2];
        if(pipe(fd)==-1){perror("demo");exit(1);}
        if (pid == -1)   {perror("demo"); exit(1);}
        fprintf(STDERR, "\npid: %d", pid);
        else if (pid==0)
        {
            fprintf(STDERR, "\npid: %d", pid);
            dup2(fd[1],1);
            printf("son\n");
            int a = execlp(cmd,cmd,arg,NULL);
            perror("demo");
        }
        else
        {
            printf("pai\n");
            while((d=read(fd[0],buffer,1000))>0) {
            buffer[d] = '\0';
            printf("<<<<%s\n",buffer);
        }
        waitpid(pid, &status, 0);
    
    
        }
    }
    I've changed the value '1' to fd[0] on read, thanks for pointing that out.

    About the fprintf's, I won't be able to get the value from the second fprintf since when I run my program it never enters the (pid==0) section.

    I'm not being able to use that first printf aswell because I get this error :

    soluis2.c:142: error: expected expression before ‘else’

    Thanks!

  8. #23
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    Ah yeah, sorry, my fprintf got in the way of your if statement.

    Code:
    void map(char* cmd, char* arg){
        int i;
        int d=0;
        FILE *stream;
        int status;
        char buffer[1000];
        stream = fopen("merdas.txt","a");
        int fd[2];
        if(pipe(fd)==-1){perror("demo");exit(1);}
        int pid = fork();
        fprintf(stderr, "\npid: %d", pid);
        if (pid == -1)   {perror("demo"); exit(1);}
        else if (pid==0)
        {
            fprintf(stderr, "\npid: %d", pid);
            dup2(fd[1],1);
            printf("son\n");
            int a = execlp(cmd,cmd,arg,NULL);
            perror("demo");
        }
        else
        {
    I've moved your fork() down a bit. It's best to check the error return soon after calling a function, so I've put that near the check but not too near.

    Then straight away print the pids. That should print the parent pid and the child pid.

    I can't see anything wrong, so this should work, hopefully! Well, I guess we haven't got as far as the execlp call yet.


    edited -- sorry, stderr should have been lower case.
    Last edited by smokeyangel; 06-01-2013 at 02:21 PM.

  9. #24
    C Beginner
    Join Date
    Dec 2011
    Location
    Portugal
    Posts
    187
    Thanks.
    It's printing the pids as following :

    pid: 1355
    pid: 0
    pid: 0

    On the father, it's already reading two lines from the the exec output :

    Code:
    printf("<<<<%s\n",buffer);
    With this printf I'm already obtaining two lines.

    The exec output has around 15 lines though, any idea why it's not printing the rest ?

  10. #25
    C Beginner
    Join Date
    Dec 2011
    Location
    Portugal
    Posts
    187
    Alright, my mate managed to get it working!

    Thanks so much!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Help using pipes
    By demonofnight in forum C++ Programming
    Replies: 5
    Last Post: 12-27-2011, 08:48 AM
  2. Pipes
    By Sharan in forum C Programming
    Replies: 1
    Last Post: 02-08-2006, 06:51 AM
  3. pipes in c
    By ajal1 in forum C Programming
    Replies: 6
    Last Post: 10-29-2005, 03:29 PM
  4. pipes
    By moi in forum C Programming
    Replies: 8
    Last Post: 08-11-2004, 01:59 PM
  5. Need some help with pipes please.
    By carrja99 in forum C Programming
    Replies: 1
    Last Post: 05-05-2004, 04:13 PM