I am trying fork for the very first time. I have a file with list of integers and I want every line to fork off a child, the child processes the line and writes something in the output file. Basically the for loop starts with number of lines in the input file and goes in a loop, every line should fork a child and after the child is done the fork should launch another child. I am having trouble doing this because before the first child finishes its work the second child starts and in between the parent is also doing some execution.
Edit: the code looks something like this:
void dosomething(flag)
{
}
void forkingfunction(int size, int array[],char *outputfile)
{
int i,j,starting=1,temp=1,status;
for(i=0;i<size;i++,temp++)
{
pid_t pID = fork();
if (pID == 0) // child
{
printf("\nchild pid %d\n",getpid());
const int count = dosomething(flag);
if(flag==1)
{
_exit(EXIT_SUCCESS);
kill(pID,SIGKILL);
}
else
{
FILE *fp;
fp = fopen(outputfile, "a+");
if (fp == NULL)
{perror("Unable to open the output file:");}
for (i = 0; i < len; i++)
{
if (solution[i])
{
fprintf(fp," %u ",array[i]);
}
}
fprintf(fp,"=%d\n",sum);
}
_exit(EXIT_SUCCESS);
kill(pID,SIGKILL);
}
else if (pID < 0) // failed to fork
{
perror("Failed to fork:");
}
else
{
// wait(NULL);
if ((pID = wait(&status)) == -1)
{
perror("Error in wait:");
}
}
}
}
void readingfile(char *inputfile,char *outputfile)
{
FILE *myFile = fopen(input, "r");
if (myFile == NULL)
{
perror("Error: Failed to open file.");
}
//code to get number of lines
while ((c=getc(myFile)) != EOF)
{
//puts values of file in an array for processing
}
forkingfunction(size,array,output);
// close file
fclose(myFile);
}
int main(int argc, char **argv)
{
readingfile(inputfilename,outputfilename);
return 0;
}
You use a single call to wait()
:
else
{
// wait(NULL);
if ((pID = wait(&status)) == -1)
{
perror("Error in wait:");
}
}
That (or using waitpid()
instead) is the core of the answer to your problem, but…
You need a different variable than pID
to hold the return value to make sure you got the right dead child because the relevant PID was in pID
before it got clobbered.
If you have other processes running in the background from this process, you might get one of those instead of the child you just launched, so you need to test whether the PID that's reported by wait()
is correct, and try again if not. That means you need a loop like:
int corpse;
int status;
while ((corpse = wait(&status)) != pID && corpse != -1) // Or corpse > 0
{
/* maybe report on what died */
}
Or you can use waitpid()
to directly wait for the relevant child to die:
int corpse;
int status;
while ((corpse = waitpid(pID, &status, 0)) != pID && corpse != -1)
{
/* maybe report on what died */
}
The wait()
and waitpid()
calls terminate with an error if there are no children left to wait for, or the specified PID no longer exists. This could happen if code somewhere else in the program waits for a process to die. It's as well to handle that; you don't want your loop locking up when the system says "there are no children left" or "that process you asked about doesn't exist". It can also happen if you have a signal handler for SIGCHLD
and it does some waiting.
In both cases, you might need to decide what to do if corpse == -1
after the loop. It shouldn't happen, but… You may legitimately decide to do nothing.
Note that a process might inherit children it didn't know about (didn't create) if a parent process (call it Program1
) forks some child processes and then uses exec*()
to replace itself with another program, Program2
. Program2
has no idea that its process is the parent of other children it did not create. Is this plausible? Yes, it can be done; I have test code that does it. Is it probable? No; it requires an unusual setup, but it isn't hard to do. For example, if a shell script launched some background processes and then issued exec program-that-forks
, the process for the program that forks has the background processes that the shell created as children, even though the program that forks did not create those processes.