Spark8006
Spark8006

Reputation: 685

Reading and writing about PIPE in linux

A simple multi-process program in linux. Input some numbers like ./findPrime 10 20 30. The program will create 3 child processes to find out all primes between 2-10, 10-20, 20-30. Once a child process find a prime, it will write "2 is prime" through a pipe and send to the parent. Parent will print it on the screen. THE PROBLEM here is that, I use a while loop to write message into the pipe and use another while loop on the parent side to receive the message, but with the code below, it only display the first message, so I am wondering what`s going on, how can i keep reading from that pipe? Did I miss someting? Thanks very much!

char readBuffer[100];
char outBuffer[15];
int pids[argc]; 
int fd[2];
pipe(fd);

for(i = 0; i < argc; i++)
{
    if( i == 0)
        bottom = 2;
    else
        bottom = args[i - 1];
    top = args[i];

    pids[i] = fork();

    if(pids[i] == 0)
    {
        printf("Child %d: bottom=%d, top=%d\n", getpid(), bottom, top);

        close(fd[0]);

        j = bottom;
        while(j <= top)
        {
            int res = findPrime(j);

            if(res == 1)
            {
                sprintf(outBuffer, "%d is prime", j);
                write(fd[1], outBuffer, (strlen(outBuffer)+1));
            }

            j++;
        }

        exit(0x47);
    } 
    else if(pids[i] < 0)
    {
        fprintf(stderr, "fork failed!  errno = %i\n", errno);   
        break;
    }
    else
    {
        close(fd[1]);
        while((nbytes = read(fd[0], readBuffer, sizeof(readBuffer))) > 0 )
            printf("%s\n", readBuffer);

        int status = 0;
        pid = waitpid(pids[i], &status, 0);

        if(pid >= 0)
            printf("Child %d exited cleanly\n", pid);
    }
}

And these child process should run in the order that they were created, like when Process 1 is done, then Process 2 will run, and process 3 will after 2. I also want the parent process display the message immediately when it receives one.

Upvotes: 4

Views: 5179

Answers (1)

Duck
Duck

Reputation: 27572

Parent/children share their file descriptors (as they presently are) at the time of the fork. Your immediate problem is that you close fd[1] in the parent. When the first child ends the fact that the process ends means that fd[1] will be automatically closed in the child. As the OS no longer has any valid references to the file descriptor it becomes invalid. So your pipe writes fail in all subsequent children.

So just don't close fd[1] in the parent.

But then you have other problems too. One that jumps out is that if one of your child processes doesn't find a prime it will never write to the pipe. The parent, however, will block forever waiting for something to read that is never going to arrive. By not closing fd[1] in the parent you won't see EOF - i.e. read() == 0 in the parent. So one solution is to pass a "done" message back via the pipe and have the parent parse that stuff out.

A better solution yet is to consider a redesign. Count the number of processes you are going to need by parsing the command line arguments right at the beginning of the program. Then dynamically allocate the space for the number of pipe descriptors you are going to need and give each process its own pair. That could avoid everything altogether and is a more standard way of doing things.

Upvotes: 6

Related Questions