Question

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

   int main(int argc, char **argv){
       int n = atoi(argv[1]);
       int superdaddy = getpid();
       int p[n+1][2];
       int i=0;
       int cpid,output;
       int result = 0;

       if(pipe(p[0])<0){
           perror("1");
           return 1;
       }
       if(pipe(p[n])<0){
           perror("2");
           return 1;
       }
       output = p[0][1];
       if(getpid()==superdaddy){
           if(write(p[0][1],&result,sizeof(result))<0){
               perror("3");
               return 1;
           }
           if(close(p[0][1])<0){
               perror("4");
               return 1;
           }
       }
       while(1){
           if(i==n){
               if(read(p[n-1][0],&result,sizeof(result)<0)){
                   perror("5");
                   return 1;
               }
               result++;
               output = p[n][1];
               if(write(output,&result,sizeof(result))<0){
                   perror("6");
                   return 1;
               }
               if(close(p[n-1][0])<0){
                   perror("7");
                   return 1;
               }
               if(close(p[n][1])<0){
                   perror("8");      
                   return 1;
               }
               break;
           }
           i++;
           cpid = fork();
           if(cpid==0){
               if(i==n)
                   continue;
               if(pipe(p[i])<0){
                   perror("9");
                   return 1;
               }
               if(read(p[i-1][0],&result,sizeof(result))<0){
                   perror("10");
                   return 1;
               }
               result++;
               output = p[i][1];
               if(write(output,&result,sizeof(result))<0){
                   perror("11");
                   return 1;
               }
               if(close(p[i-1][0])<0){
                   perror("12");
                   return 1;
               }

               if(close(p[i][1]<0)){
                   perror("13");
                   return 1;
               }
               continue;
           }
           else if(cpid<0){
               perror("14");
               return 1;
           }
           break;
       }

       if(getpid()==superdaddy){
           wait(NULL);
           if(read(p[n][0],&result,sizeof(result))<0){
               perror("15");
               return 1;
           }
           printf("Result: %d\n",result);
           if(close(p[n][0])<0){
               perror("16");
               return 1;
           }
       }
       return 0;
   }

The Program aims to read a number n from command line and then forks n child process and create n pipes. process p0 will be parent of process p1, p1 will be parent of p2, so and so on. One variable (named result here) will be passed through pipes, every time it is passed it will be added by 1. So the output should be n as well. Pipe Fi connects Pi and P(i+1). Attached is my code.

When n=1 or n=2, the program can output correctly, which is 1 and 2 correspondingly. However, when n=3, it gives me a bad file error at error 5. I have hand-tracked the code for the whole afternoon but got no idea what is wrong with it. Anyone could help? Appreciate it first!

Was it helpful?

Solution

when n=3, it gives me a bad file error at error 5.

This could be fixed by removing that if(close(p[i][1]<0)){ in your code, because you need to read from p[i][0] in your last iteration, i.e.

if (i == n) {
    if(read(p[n-1][0],&result,sizeof(result)<0)){
        ...
    }
}

This is an implementation of your idea, I hope it may be helpful:

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

int
main(int argc, char *argv[])
{
    if (argc != 2) {
        fprintf(stderr, "Usage: %s N\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    int n = atoi(argv[1]);
    int pipes[n][2];
    int i, val;
    pid_t pid;

    val = 0;

    for (i = 0; i < n; i++) {
        if (pipe(pipes[i]) < 0) {
            perror("pipe");
            exit(EXIT_FAILURE);
        }
        if ((pid = fork()) < 0) {
            perror("fork");
            exit(EXIT_FAILURE);
        }
        else if (pid == 0) {
            close(pipes[i][1]);
            if (read(pipes[i][0], &val, sizeof(val)) != sizeof(val)) {
                perror("read");
                exit(EXIT_FAILURE);
            }

            printf("C %d read %d\n", getpid(), val);

            val++;
        }
        else {
            close(pipes[i][0]);

            printf("P %d writes %d\n", getpid(), val);

            if (write(pipes[i][1], &val, sizeof(val)) != sizeof(val)) {
                perror("write");
                exit(EXIT_FAILURE);
            }

            if (waitpid(pid, NULL, 0) != pid) {
                perror("waitpid");
                exit(EXIT_FAILURE);
            }
            printf("%d is going to leave.\n", getpid());
            exit(EXIT_SUCCESS);
        }
    }

    printf("%d is going to leave.\n", getpid());
    exit(EXIT_SUCCESS);
}

Testing run:

$ ./a.out 3
P 2005 writes 0
C 2006 read 0
P 2006 writes 1
C 2007 read 1
P 2007 writes 2
C 2008 read 2
2008 is going to leave.
2007 is going to leave.
2006 is going to leave.
2005 is going to leave.

Explanation:

The frame of that code is for (i = 0; i < n; i++) { pipe(); fork(); }, which means it will create n pipes, and n new processes. In each iteration, the parent will write to pipes[i][1] and child will read from pipes[i][0]. Eventually, it will create a process chain connected by a series of pipes, and a value is passed down from the first process to the last through that series of pipes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top