Currently working on some homework and having a hard time. The goal is to generate 100,000 numbers and add them all together by dividing the work into 10 processes (10,000 numbers each)
I think I've figured out how to fork processes (hopefully), but using Pipe() to relay the subtotals from each child process is not working... the program below returns 44901 for each child process and 449010 for the running total.
I'm struggling hard but I feel like this is something simple I should be able to understand.
main()
{
int i;
pid_t pid;
int status = 0;
int fd[2];
int runningTotal = 0;
pipe(fd);
int t;
int r;
for (i = 0; i < 10; i++) {
pid = fork();
if (pid == 0){
close(fd[0]);
t = ChildProcess();
write(fd[1], &t, sizeof(t));
exit(0);
}
close(fd[1]);
read(fd[0], &r, sizeof(r));
runningTotal = runningTotal + r;
wait(&status);
}
printf("%i\n", runningTotal);
}
int ChildProcess() {
int i;
int total = 0;
int r = 0;
for (i = 0; i < 10000; i++) {
r = rand() % 10; // 0 to 10
total = total + r;
}
printf("%i\n", total);
return total;
}
given this code: (an excerpt from the posted code)
there is a sequence problem.
When the parent closes the fd[1] during the first iteration of the loop, that file descriptor does not 'magically' open again for the next iteration of the loop.
The code for the parent, in the loop, needs to check the returned value from the call to
read()
to assure the operation was successful. (it probably was not successful after the first iteration through the loop, so the variable 'r' will be unchanged.Ordinarily, one would use a separate pipe for each child, for otherwise it's impossible for the parent to know from which process the data it reads comes. I don't think that's so much of an issue in this particular case, though, because here, you actually don't care. Although it still makes me cringe a bit, I think you indeed can get away with just one pipe for this particular task.
In fact, I don't think your problem is with the pipe at all. It is with
rand()
. All child processes compute exactly the same sequence of (pseudo-)random numbers because they all use the same (default) seed. If you want to produce different sequences of numbers, then you need to callsrand()
in each child process, giving a different seed in each one. The sequence of numbersrand()
will generate is completely determined by the seed with which it starts.Note, too, that if the system's random number generator is any good at all, then all the sums computed by the various processes should be very close to each other, and to the result you reported. This is a consequence of the Central Limit Theorem in statistics, but you can think of it simply as the larger results balancing the smaller ones on average. There's probably a slight bias arising from calculating the remainder mod 10.
Initial diagnosis
If your concern is that the children are all producing the same values, then the problem is that they're all using the same random sequence because you don't call
srand()
anywhere. You need to call it once per child, with a different seed for each child.It isn't 100% reliable, but you could probably get away with
srand(time(0) + getpid());
in each child — or even justgetpid()
since those values are guaranteed to be different.Further scrutiny
Actually, on closer examination, there's another problem. The parent process closes the write end of the pipe after forking the first child, so the subsequent children don't have a usable file descriptor to use. The read value will always be the one from the first child. So, you need to do more serious work.