Multiple children and single pipe

Greetings everyone, I need a bit of help in solving the following problem:
I'm given an array of numbers and I have to compute the sum of the array elements using n processes, and the inter process communication has to be done with pipes(one pipe, to be exact).

I managed to solve the problem by waiting for a random child to finish, reading the sum sent by the child through the pipe, and so on for the following children, and incrementing the final sum.

Now I have to solve it by reading the partial sums in one fell swoop, after all the children have finished, and I'm not sure as to how to save the entire information sent by the kids. I tried to use a for statement, but it failed, since all the information would be passed in one single element of the array, and offering only the address of the first element in the array failed as well.

Any input would be much appreciated.

Here is the code that's bugging me:

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 
#include <stdlib.h> 
 
 
 
void main () { 
 
        int size, fd [2]; 
        printf ("enter the size of the number array: "); 
        scanf ("%d", &size);
        int i, arr ;
        for(i=0; i < size; i++)
           arr  = i + 1;
         
 
        int nr_proc; 
        printf ("enter the number of processes that you want to use: "); 
        scanf ("%d", &nr_proc); 
        pid_t pid [nr_proc];
         
        for (i = 0; i < nr_proc; i++) { 
           pipe (fd); 
           pid  = fork (); 
           if (pid  < 0) 
              printf ("error in fork.\n"); 
           if (pid  == 0) { 
              close (fd [0]); 
              int j = 0, sum = 0; 
              for (j = i * size/nr_proc; j < (i+1) * size/nr_proc; j++) { 
                sum += arr[j]; 
              } 
              printf ("test %d\n", sum); 
              write(fd [1], &sum, sizeof (int)); 
              exit (1); 
           }
        } 
        close (fd [1]);
        for (i = 0; i < nr_proc; i++)
           wait ();
        int aux[nr_proc], test = 0;
        read (fd [0], aux, sizeof(aux));  // this is where i need help
        printf ("test aux %d\n", aux [1]);
        int sum = 0;
        for (i = 0; i < nr_proc; i++) 
           sum += aux ;
        printf ("result = %d\n", sum);
              
} 

Your description of what needs to be done isnt very clear so start off by explaing your problem clearly...

Sorry about that, I'm not a native english speaker. I'll try to give an example:

suppose we have this array:
arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
I want to compute the sum of it's elements using 2 child processes, to do so we'll split the array in two equal(or almost equal, if the number of elements is an odd number), and the first child will compute:
(1+2+3+4+5 = 15)
while the second will do:
(6+7+8+9+10 = 40).

Now, each child will send their computed sum to the parent through the pipe fd(2). The problem I'm having is that I don't know how to save both sums at the same time, that is, if I try to read the sums after all kids have finished, for example
int buffer[2];
read (fd (0), buffer, sizeof (buffer));
will first assign 15 to buffer [0], and then he'll assign 40 to buffer [0] , and i want it to assign 15 to buffer [0] and 40 to buffer [1]

Then how about creating 2 pipes...this way one child's output is read into buffer[0] and the other child's output is read into buffer[1].

That doesn't happen, the child doesn't magically cause read() to rewind and overwrite array index 0. They don't control that.

Check how many bytes you actually read. You may have to read more than once.

You're not guaranteed to get them in order, either.

You're not even guaranteed to not get one number written inside another, unless you do advisory locking on the pipe in your children.

Corona, that's my exact problem, I'm not allowed to make multiple reads this time, I already solved it that way by waiting for a child, reading the pipe, repeat :smiley: . I have to figure out a mechanism that allows me to read everything in the pipe at once, and store it, been googling for pipe I/O for a few hours now to no avail :wall:.

How do you know you didn't read enough data? You don't even check what value read() returns.

You're closing all the write-ends and waiting for all the processes to return first, so conditions should be ideal.

I followed your advice on checking the returned value of read () and write (), read returns 4 bytes, which is the same as what write() returns, I believe that means I only get the chance to read the input from the child that finishes last, as he overwrites the pipe ?

At this point I only see 2 solutions for the problem, the one I already solved, and having a pipe for every child like shamrock suggested(an array of pipes maybe ?), will try the sham's proposal.

But if you are allowed to call read only once in the parent then it wont work as my solution requires 2 reads. Going over your posted code it looks like you start with one parent then fork creating a child which then forks itself creating another child...so you end up having a parent a child and a grandchild. Is that how you are supposed to approach it as that simplifies things and makes it completely doable with a single read in the parent.

If you follow the code more closely you'll notice that it's only the parent that calls fork(), so what i have is a parent with n children processes.

Easy way to check this, do:

int pid = getppid(); // pid = parent's pid
printf ("pid = %d\n", pid);

inside of if (pid [i]== 0) { } , you'll get the same parent pid for each of the n children.

int aux[nr_proc]

you should give this a fixed number not a variable. sizeof() is set at compile-time and knows nothing about variable-size arrays. I think sizeof() is only giving you 4.

I tried to do that, it still returns 4, which is also the size of an int in my debian.

In your code, you are creating pipe inside loop

for (i = 0; i < nr_proc; i++) {
     pipe (fd);

So you are losing data of previous child, try to keep it above for loop and try...

I can't believe how simple that was, it works now. You have my sincere gratitude !

I missed it too :o Interesting.