0

I'm trying to make a program in c that forks a child and has two way communication using two separate pipes.

Summarizing;

  1. The father writes into pipe1
  2. The child reads from pipe1 and make the calculations
  3. The child writes the answer in pipe2
  4. The father reads the information from pipe2

It is all going well till step 3, if I comment the code from point 4 then it all works and I even check for the write to pipe2 and it seems to work, but when I try to read from pipe2 in the father code it hangs and does not even executes the child calculations, step 2 and 3. please help me. this is my code so far.

int main(int argc, char *argv[]) {

pid_t pid;
pid_t* trabajadores;

int nHijos = 1;

trabajadores = (pid_t*)malloc(sizeof(pid_t) * nHijos);

int** aHijos;
int links = 0;

// Matriz de pipes
aHijos = (int **) malloc(sizeof(int *) * nHijos);
for (i = 0; i < nHijos; i++) {
    aHijos[i] = (int *) malloc(sizeof(int)*2);
}

int alPadre[2];
pipe(alPadre);

// Se crea el pool de procesos
for (i = 0; i < nHijos; i++) {

    pipe(aHijos[i]);
    pid = fork();

    if (pid == 0) {

        int j;
        FILE* salidaHijo;
        FILE* entradaHijo;
        char buffer2[1024];
        close(alPadre [0]);
        for (j = 0; j<i; j++) {
            close(aHijos[j][0]);
            close(aHijos[j][1]);
        }
        close(aHijos[i][1]);

        entradaHijo = fdopen(aHijos[i][0], "r");


        // STEP 2
        while ( !feof (entradaHijo) &&  fgets (buffer2, sizeof (buffer2), entradaHijo) != NULL) {
            buffer2[strcspn(buffer2, "\n")] = 0;
        }

        char* resultado;


        /* CALCULATIONS */





// STEP 3
        salidaHijo = fdopen(alPadre[1], "w");
        printf("%i\n", fprintf(salidaHijo, "%s\n", resultado));
        fflush (salidaHijo);

        exit(0);

    } else {
        trabajadores[i] = 0;
        close(alPadre[1]);
        close(aHijos[i][0]);


        // STEP 1
        FILE** salidaPadre;
        salidaPadre = (FILE**)malloc(sizeof(FILE*) * nHijos);
        for (i = 0; i < nHijos; i++) {
            salidaPadre[i] = fdopen(aHijos[i][1], "w");
        }
        fprintf(salidaPadre[j], "%s\n", DesencolarT(trabajos));
        trabajadores[j] = 1;


        sleep(5);


        // STEP 4
        char buffer[1024];
        entradaPadre = fdopen(alPadre[0], "r");
        read(alPadre[0], buffer, sizeof(buffer));
        while ( !feof (entradaPadre) &&  fgets (buffer, sizeof (buffer), entradaPadre) != NULL) {
            printf("%s\n", buffer);

        }
    }
}
return 0; 
}

that wont compile it is just a pasted part of my code, here is the output from strace -ff -o test.log ./myProg for the two processes.

getdents(4, /* 0 entries */, 32768)     = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7761000
write(1, ". 160\n", 6)                  = 6
fcntl64(6, F_GETFL)                     = 0x1 (flags O_WRONLY)
fstat64(6, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7760000
_llseek(6, 0, 0xbfb8895c, SEEK_CUR)     = -1 ESPIPE (Illegal seek)
read(3, 0xbfb89738, 1024)               = ? ERESTARTSYS (To be restarted)
--- SIGINT (Interrupt) @ 0 (0) ---
+++ killed by SIGINT +++

AND

close(3)                                = 0
close(6)                                = 0
fcntl64(5, F_GETFL)                     = 0 (flags O_RDONLY)
fstat64(5, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7761000
_llseek(5, 0, 0xbfb8895c, SEEK_CUR)     = -1 ESPIPE (Illegal seek)
read(5, 0xb7761000, 4096)               = ? ERESTARTSYS (To be restarted)
--- SIGINT (Interrupt) @ 0 (0) ---

Thank you, sorry for the spanish the long post and the horrible formatting.


Using fflush() after step 1 and 3 I got to a point in where if I close pipe1() after step 1 everything works, the problem is that I need to keep writing to that child in the future so I can't close it.

Josepas
  • 349
  • 1
  • 2
  • 12
  • The posted code doesn't compile, is it missing some parts? (you'll get better help if people can compile the posted code in order to see how it works/doesn't work for them) – Jeremy Friesner Mar 05 '15 at 05:03
  • `pipe` does not exist in standard C99 or C11. It is a POSIX or Linux call. So you should tag your question with POSIX or Linux. – Basile Starynkevitch Mar 05 '15 at 06:40

1 Answers1

1

In your parent, you don't want to close the write side of the pipe to the parent close(alPadre[1]); because then your subsequent children won't be able to talk to the parent using that pipe.

Indeed, your subsequent calls to close(alPadre[1]); in later loop iterations may unintentionally be closing other "random" file descriptors in the parent, as it will close whatever file descriptor number alPadre[1] happens to be at that time. After you close any file descriptor you likely want to set that variable's value to -1 so that no further calls using that variable will have any effect.

As another example, in your child process you call close(aHijos[j][0]); for all j < i. Here again, most of these file descriptors were previously closed by the parent before the fork, so you are again "randomly" closing whatever file descriptor numbers happen to be at aHijos[j][0] for all j < i.

Also, your parent eventually needs to close the write side of the pipe it uses to talk to each child, or the child will wait forever for more input in its input loop. That is likely why your parent hangs at step #4, because your child is hanged at step #2 waiting for an EOF on the pipe from the parent.

jschultz410
  • 2,849
  • 14
  • 22
  • Ok, I don't understand why shouldn't I have to close alpadre(1) in the parent code because that is the pipe the father is using to read from his children, the write end of that pipe is for the children to use. Ok, I have the parent code outside the loop now, and I am not closing alpadre (1) in the father, but still doesn't work – Josepas Mar 05 '15 at 11:38
  • and I cant close the writing end of the parent because it is a processes pool and I want to be able to send more jobs from parent to his children and answers from them using the second pipe – Josepas Mar 05 '15 at 11:54
  • 1
    @Josepas The main problem with your logic is that your parent never closes the write side of the pipe to the child (after sending it the appropriate input). Therefore, the child will block in its input loop as it will wait forever for more input from the parent until it gets an EOF. Closing the write side of the pipe in the parent will send an EOF to that client, allowing it to finish. – jschultz410 Mar 05 '15 at 16:11