user9062823
user9062823

Reputation:

Pipe() and fork()

The goal of my program is to create two pipes and two processes that communicate each other reading and writing to the pipes.

  1. process p1 reads from pipe c1 and writes to the pipe c2
  2. process p2 reads from pipe c2 and writes to the pipe c1

Until the read number from the pipe is less than BIG_INT_STOP the two processes continue to increment the number in the pipes. As soon as this condition is true, first process that reads it, close the pipes, exit and prints the number. The problem is: when the process p2 ends before p1 it works and when the process p1 ends before p2 it goes in loop. Can you explain me why?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sysinfo.h>
#include <sys/wait.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#define BIG_INT_STOP 40
#define TEST_ERROR    if (errno) {fprintf(stderr, \
                  "%s:%d: PID=%5d: Error %d (%s)\n", \
                  __FILE__,         \
                  __LINE__,         \
                  getpid(),         \
                  errno,            \
                  strerror(errno));}

int main(){
  int c1[2], c2[2], p1, p2, z;
  long a = 0, c;
  pipe(c1);
  pipe(c2);
  write(c1[1], &a, sizeof(a));
  write(c2[1], &a, sizeof(a));
  p1 = fork();
  p2 = fork();
  switch(p1){
    case -1:
      TEST_ERROR;
      exit(EXIT_FAILURE);
    case 0:
      read(c1[0], &c, sizeof(c));
      while(c != BIG_INT_STOP){
        ++c;
        write(c2[1], &c, sizeof(c));
        read(c1[0], &c, sizeof(c));
      }
      close(c1[0]);
      close(c1[1]);
      close(c2[0]);
      close(c2[1]);
      printf("p1: %ld\n", c);
      exit(0);
  }
  switch(p2){
    case -1:
      TEST_ERROR;
      exit(EXIT_FAILURE);
    case 0:
      read(c2[0], &c, sizeof(c));
      while(c != BIG_INT_STOP){
        ++c;
        write(c1[1], &c, sizeof(c));
        read(c2[0], &c, sizeof(c));
      }
      close(c1[0]);
      close(c1[1]);
      close(c2[0]);
      close(c2[1]);
      printf("p2: %ld\n", c);
      exit(0);
  }
  while(wait(&z) != -1);
}

Upvotes: 0

Views: 139

Answers (3)

Chris Turner
Chris Turner

Reputation: 8142

Your code doesn't do proper error checking on the calls to read and write which means that if there is a problem reading from the pipes, the child will enter a never ending loop as the value of c will never reach the termination value.

Since your child processes close the pipes when they're done, you have a very high chance of entering a race condition where one process closes the pipes before the other has read in the latest value of c. This is compounded by the placement of your calls to fork as currently you end up with 3 child processes not 2.

You should move the second call to fork after the switch as you know that at that point you can only be in the parent process and also move the closing of the pipes to the parent.

Upvotes: 0

Nodarius
Nodarius

Reputation: 276

Problem is p2 is forked 2 times. Once in parent process, and second time in p1 process.

Instead of:

  p1 = fork();
  p2 = fork();

You need to write like this:

p1 = fork();
if (p1 > 0) {
        p2 = fork();
}

Upvotes: 1

Marian
Marian

Reputation: 7482

Your program is a bit strange. The main problem seems to be that the second fork is executed in both main program and in the first child. In fact you are running four processes: main, two sons of main and the son of the first son. This is probably not what you want. You probably wanted to put the first switch immediately after the first fork and to execute the second fork only in the main program.

And, of course, you are not checking result values of read and write for unexpected situations.

Upvotes: 3

Related Questions