3

I'm studying IPC using pipes. The parent process creates 'n' number of child processes and waits until all children processes terminate. I want the first child to be notified when all it's sibling processes terminate. I'm exploiting the fact that the read() blocks till all it's WRITE ends are closed. So, it's siblings close() the WRITE end upon completing their work.

The problem in my code is, the read() in the first child does not unblock at all and the first child does not terminate and hence the parent continues to wait.

What is it that I'm doing wrong?

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{

    int fd[2]; // 0 = READ end, 1 = WRITE end
    int ret = pipe(fd);

    pid_t wait_pid;
    int status = 0;

    int n = 4;

    for(volatile int i = 0;i < n;++i) {

        ret = fork();
        if(ret == -1) {
            fprintf(stderr, "fork failed\n");
            exit(1);
        }

        switch(ret) {
            // child
            case 0: {
                fprintf(stderr, "Child created : %d\n", getpid());
                if(i!=0) {
                    close(fd[0]); // close unused READ end
                    foo();        // do some work                       
                    close(fd[1]); // close WRITE end, the last child
                                  // to close will cause the read()
                                  // of first child to unblock
                }
                if(i==0) { // first child    
                    close(fd[1]); // close unused WRITE end
                    foo();        // do some work                       
                    char c = 0;
                    fprintf(stderr, "1st Child's wait started %d\n",
                        getpid());
                    read(fd[0], &c, 1); // blocking call, until all
                                        // siblings close the WRITE
                                        // end
                    fprintf(stderr, "1st Child's wait over %d\n",
                        getpid());
                    close(fd[0]); // close READ  end
                }       
                fprintf(stderr, "Child %d terminating\n", getpid());            
                exit(0);
                break;
            }
        }
    }

    // Parent waits for all childdren to finish
    while ((wait_pid = wait(&status)) > 0);
    fprintf(stderr, "Parent's wait over, now terminating...\n");

    return 0; 
}
jxh
  • 69,070
  • 8
  • 110
  • 193
user7413
  • 37
  • 8
  • You need to use Inter-Process Communication (IPC) among child processes which allow processes to communicate each other and synchronize their actions. – H.S. Nov 10 '17 at 17:29
  • That's what my program does, no? :) – user7413 Nov 10 '17 at 17:43
  • Why don't you use some synchronization primitives like semaphores? – H.S. Nov 10 '17 at 18:12
  • Well, I could. But I'm curious what am I doing wrong in above case :) – user7413 Nov 10 '17 at 18:22
  • Possible duplicate of [Multiple child processes reading/writing on the same pipe](https://stackoverflow.com/questions/7152654/multiple-child-processes-reading-writing-on-the-same-pipe) – OznOg Nov 10 '17 at 18:29
  • The only similarity is "pipe between multiple child processes". The other user is trying to achieve something completely different, I'm not even trying to write to the pipe. Moreover, that question has no accepted answer. – user7413 Nov 10 '17 at 18:47

1 Answers1

3

The problem with your technique is that the parent itself also has a copy of the file descriptors created by the pipe.

Close the descriptors after the fork loop is done.

jxh
  • 69,070
  • 8
  • 110
  • 193