Dennis Vash
Dennis Vash

Reputation: 53884

What is wrong with wait() on father process in pipeline

I have been asked:

  1. What is wrong in the next code?
  2. How to fix it in son's process code:
#define BUF_SIZE 4096
int my_pipe[2];
pipe(my_pipe);
char buf[BUF_SIZE];
int status = fork();

//Filled buf with message...
if (status == 0) {  /* son process */
    close(my_pipe[0]);
    write(my_pipe[1],buf,BUF_SIZE*sizeof(char));
    exit(0);
 }
 else {    /* father process */
    close(my_pipe[1]);
    wait(&status);  /* wait until son process finishes */
    read(my_pipe[0], buf, BUF_SIZE*sizeof(char));
    printf("Got from pipe: %s\n", father_buff);
    exit(0);
 }
}

So I came up with the next code to try and conduct the problem:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

#define BUF_SIZE 6

int main() {
    int my_pipe[2];
    pipe(my_pipe);

    char buf[BUF_SIZE];
    int status = fork();
    //Filled buf with message...
    for (int i = 0; i < BUF_SIZE; i++) buf[i] = 'a';

    if (status == 0) {    /* son process */
        close(my_pipe[0]);
        write(my_pipe[1], buf, BUF_SIZE * sizeof(char));
        _exit(0);
    } else {    /* father process */
        close(my_pipe[1]);
        wait(&status);    /* wait until son process finishes */
        printf("Son Status: %d\n", status);
        read(my_pipe[0], buf, BUF_SIZE * sizeof(char));
        printf("Got from pipe: %s\n", buf);
        _exit(0);
    }
}

My first thoughts were that there is a problem with the wait(&status), which may cause the program not to terminate if the son process won't finish.

In the son's code, I believe if there is not enough space in the pipe, the write will block the process, and therefore block the whole application.

If my claims are right, how can I prove it? And I didn't figure out how to fix son's code.

Upvotes: 0

Views: 51

Answers (1)

Ingo Leonhardt
Ingo Leonhardt

Reputation: 9894

Your assumptions about the pipe size are right, I could reproduce the problem with a BUF_SIZE of 0x10000.

But the solution is not on the client's but on the parent's side. You just have to read() before wait() and of course you should always use the return code to determine how much you have received. This fix of the parent didn't cause blocks anymore:

    len = read(my_pipe[0], buf, BUF_SIZE * sizeof(char));
    if( len >= 0 ) {
            printf("Got %d from pipe\n", len );
    } else {
            perror( "read()" );
    }
    close(my_pipe[1]);
    wait(&status);    /* wait until son process finishes */
    printf("Son Status: %d\n", status);

In the child process you could use non-blocking IO using fcntl(my_pipe[1], F_SETFL, O_NONBLOCK); so write() would send as much as possible and then return. Of course the rest of the data would be lost in that case.

Upvotes: 1

Related Questions