'Two way communicating with pipes - in the correct order

I have a small program to demonstrate two way communication with pipe between parent and child processes. I already asked a question about this (Two way communicating using pipe).

So I have a parent process and two child processes (child_a, child_b). I use 4 pipes for communicating between processes: pipefd_a1 and pipefd_b1 for parent-child, pipefd_a2 and pipefd_b2 for child-parent communicating. First the parent calculating some data and collecting these in two arrays (rabbits_a and rabbits_b). These arrays containing struct Rabbit elements. Then the parent process sends rabbits_a to child_a and rabbits_b to child_b. The child processes process the sent data then send back to parent. Everything is working fine until this moment. When parent comes to read these datas the program just hangs and seems like it never returns from the while (read) loop. I'm sure that I close all the pipes correctly, but I think the problem is that I'm closing one of the pipes at the wrong time. Can anyone help me what the problem could be?

The relevant code snippet:

int pipefd_a1[2], pipefd_a2[2];
int pipefd_b1[2], pipefd_b2[2];
pid_t child_a, child_b;

if (pipe(pipefd_a1) != 0 || pipe(pipefd_a2) != 0 || pipe(pipefd_b1) != 0 || pipe(pipefd_b2) != 0) {
    perror("pipe");
    exit(EXIT_FAILURE);
}

//
// Calculating the datas to send
//

Rabbit** rabbits_a = (Rabbit**)malloc(sizeof(Rabbit*) * size);
unsigned count_a = 0;
for (unsigned i = 0; i < size; ++i) {
    if (iterator[i] != NULL && (strcmp("Barátfa", iterator[i]->district) == 0 || strcmp("Lovas", iterator[i]->district) == 0 || strcmp("Kígyós-patak", iterator[i]->district) == 0 || strcmp("Káposztás kert", iterator[i]->district) == 0)) {
        rabbits_a[count_a++] = add_rabbit(iterator[i]->name, iterator[i]->district, iterator[i]->part_count, iterator[i]->eggs_count);
    }
}

Rabbit** rabbits_b = (Rabbit**)malloc(sizeof(Rabbit*) * size);
unsigned count_b = 0;
for (unsigned i = 0; i < size; ++i) {
    if (iterator[i] != NULL && (strcmp("Szula", iterator[i]->district) == 0 || strcmp("Malom telek", iterator[i]->district) == 0 || strcmp("Páskom", iterator[i]->district) == 0)) {
        rabbits_b[count_b++] = add_rabbit(iterator[i]->name, iterator[i]->district, iterator[i]->part_count, iterator[i]->eggs_count);
    }
}
    
if ((child_a = fork()) < 0) {
    perror("fork");
    exit(EXIT_FAILURE);
} else if (child_a == 0) {  // Child A
    close(pipefd_b1[0]);
    close(pipefd_b1[1]);
    close(pipefd_b2[0]);
    close(pipefd_b2[1]);

    close(pipefd_a1[1]);
    close(pipefd_a2[0]);
        
    // Receiving data from parent               
    Rabbit* rabbits = (Rabbit*)malloc(sizeof(Rabbit) * size);
    Rabbit rabbit;
    unsigned count_rabbits = 0;
    while (read(pipefd_a1[0], &rabbit, sizeof(Rabbit))) {
        rabbit.eggs_count = rand() % 100 + 1;
        rabbits[count_rabbits++] = rabbit;
    }
    close(pipefd_a1[0]);

    // Sending data back to parent
    for (unsigned i = 0; i < count_rabbits; ++i) {
        write(pipefd_a2[1], &rabbits[i], sizeof(Rabbit));
    }
    close(pipefd_a2[1]);

} else if ((child_b = fork()) == -1) {
    perror("fork");
    exit(EXIT_FAILURE);
} else if (child_b == 0) {  // Child B                      
    close(pipefd_a1[0]);
    close(pipefd_a1[1]);
    close(pipefd_a2[0]);
    close(pipefd_a2[1]);

    close(pipefd_b1[1]);
    close(pipefd_b2[0]);

    // Receiving data from parent
    Rabbit* rabbits = (Rabbit*)malloc(sizeof(Rabbit) * size);
    Rabbit rabbit;
    unsigned count_rabbits = 0;
    while (read(pipefd_b1[0], &rabbit, sizeof(Rabbit))) {
        rabbit.eggs_count = rand() % 100 + 1;
        rabbits[count_rabbits++] = rabbit;
    }
    close(pipefd_b1[0]);

    // Sending data back to parent
    for (unsigned i = 0; i < count_rabbits; ++i) {
        write(pipefd_b2[1], &rabbits[i], sizeof(Rabbit));
    }
    close(pipefd_b2[1]);
} else {    // Parent
    // Sending data to child_a
    for (unsigned i = 0; i < count_a; ++i) {
        Rabbit rabbit = {rabbits_a[i]->name, rabbits_a[i]->district, rabbits_a[i]->part_count, rabbits_a[i]->eggs_count};
        write(pipefd_a1[1], &rabbit, sizeof(Rabbit));
    }
    close(pipefd_a1[1]);

    // Sending data to child_b
    for (unsigned i = 0; i < count_b; ++i) {
        Rabbit rabbit = {rabbits_b[i]->name, rabbits_b[i]->district, rabbits_b[i]->part_count, rabbits_b[i]->eggs_count};
        write(pipefd_b1[1], &rabbit, sizeof(Rabbit));
    }
    close(pipefd_b1[1]);

    // Receiving data from child_a
    Rabbit rabbit;
    while (read(pipefd_a2[0], &rabbit, sizeof(Rabbit))) {
        modify(rabbit.name, rabbit.district, rabbit.part_count, rabbit.eggs_count);
    }
    // Doesn't reach this point
    close(pipefd_a2[0]);
    
    // Receiving data from child_b
    while (read(pipefd_b2[0], &rabbit, sizeof(Rabbit))) {
        modify(rabbit.name, rabbit.district, rabbit.part_count, rabbit.eggs_count);
    }
    close(pipefd_b2[0]);

    close(pipefd_a1[0]);
    //close(pipefd_a1[1]);
    //close(pipefd_a2[0]);
    close(pipefd_a2[1]);
    close(pipefd_b1[0]);
    //close(pipefd_b1[1]);
    //close(pipefd_b2[0]);
    close(pipefd_b2[1]);
                        
    int corpse;
    int status;
    while ((corpse = wait(&status)) > 0) {
        printf("Child %d exited with status 0x%.4X\n", corpse, status);
    }
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source