* The program performs a parallel computation of an integer range sum. forksum.c receives a start and end value of an integer range and
* computes the sum of all numbers in that range. The range is split in two halves and two child processes are forked to compute the respective
* subproblem, until the recursion finally ends, when start and end of the range are the same. The program outputs the range sum and the number of forks.
* You can use and modify this program for your benchmarkings.
*/
// The Result struct contains the result of the sum operation and a counter for the number of fork operations.
typedefstructResult{
intsum;
intnum;
}Result;
// Declare functions to make them usable before the implementation.
Resultforksum(intstart,intend);
intparseInt(char*str,char*errMsg);
// spawnChild forks a subprocess to compute the sum with the given range of numbers. For computing the sum, the subprocess calls forksum().
// Before spawning the child process, spawnChild creates a bidirectional pipe. One side of the pipe is returned to the caller,
// the other side is used by the child process to output results.
intspawnChild(intstart,intend){
intpipefd[2];
if(pipe(pipefd)<0){
perror("pipe");
exit(1);
}
intchild;
while((child=fork())<0){
perror("fork");
}
if(child==0){
// In the child process: call forksum and write the results to our half of the pipe.
Resultresult=forksum(start,end);
close(pipefd[0]);
FILE*stream=fdopen(pipefd[1],"w");
if(!stream){
perror("fdopen child write pipe");
exit(1);
}
fprintf(stream,"%d\n%d\n",result.sum,result.num);
exit(0);
}
// This continues the parent process. Return our half of the pipe.
close(pipefd[1]);
returnpipefd[0];
}
// readIntLine reads a line from the given FILE and parses its contents to an int using parseInt().
intreadIntLine(FILE*stream,char*errorMsg){
size_tbufSize=1024;
char*line=malloc(bufSize);
ssize_tlen=getline(&line,&bufSize,stream);
if(len<0){
perror("read line from child");
return0;
}
line[len-1]='\0';
returnparseInt(line,errorMsg);
}
// readChild reads data from the given file descriptor and parses it to a Result struct.
// This reads the result data written by a child process in spawnChild().
ResultreadChild(intfd){
FILE*stream=fdopen(fd,"r");
if(!stream){
perror("fdopen child read pipe");
exit(1);
}
intsum=readIntLine(stream,"Failed to parse sum result from child");
intnum=readIntLine(stream,"Failed to parse num result from child");
return(Result){sum,num};
}
// forksum computes the sum of all numbers in the given range (inclusive) by spawning 2 child processes.
// One child computes the sum of the lower range, the other of the upper range.
// The two results are summed and returned.
// If the start and end parameters are equal, the result is returned directly. This is the break condition for the recursion.
Resultforksum(intstart,intend){
if(start>=end){
if(start>end)
fprintf(stderr,"Start bigger than end: %d - %d\n",start,end);
// The recursive fork arrived at a leaf process. Return our input and 1 to count this leaf process.
return(Result){start,1};
}
// First, spawn child processes for the two sub-ranges. The result is a file descriptor for a buffer where the child will write its results.
intmid=start+(end-start)/2;
intchild1=spawnChild(start,mid);
intchild2=spawnChild(mid+1,end);
// Read the results from the two file descriptors.
Resultres1=readChild(child1);
Resultres2=readChild(child2);
// Wait for the 2 child processes to exit and return the summed result.
// Add 1 to the number of processes to count the current process.