To fork off X processes and have the parent wait for all, I have the following code:
int maxProcesses = 10;
for (int currentChild = 0; currentChild < maxProcesses; currentChild++) {
pid_t pid = fork();
if (pid < 0) {
// Error
} else if (pid == 0) {
// Child
} else {
// Parent
// Should I call waitpid on pid and wait here instead?
}
}
// Wait for all children
for (int currentChild = 0; currentChild < maxProcesses; currentChild++) {
wait(NULL);
}
Now I would like to modify the code so that of X total processes, Y are forked off first, and then as they finish, more forks are made till desired total number is reached. I have made some changes to the above code, with some questions.
int totalProcessesToBeForked = 10;
int maxAllowedAtOnce = 5;
for (int currentChild = 0; currentChild < maxAllowedAtOnce; currentChild++) {
forkChild(currentChild);
}
// Wait for all children
// # How do I modify this to wait for new children forked as well
// # if I move it inside parent, it will make things easier, right?
for (int currentChild = 0; currentChild < maxAllowedAtOnce; currentChild++) {
wait(NULL);
}
void forkChild(currentChild) {
pid_t pid = fork();
if (pid < 0) {
// Error
} else if (pid == 0) {
// Child
} else {
// Parent
// # I think waiting here using waitpid will be better b/c
// # as new forks are made, parent begins to wait for them
}
}
I will probably need to keep a count of how many children have been forked and compare it to totalProcessesToBeForked, and fork new ones accordingly.
Updated Code v1:
int maxProcesses = 10;
int maxAllowedAtOnce = 5;
int main(int argc, char* argv[]) {
// Start timer
alarm(10); // Terminate after 10s
signal(SIGALRM, onTimeout);
signal(SIGCHLD, catchChild);
for (int currentChild = 0; currentChild < maxAllowedAtOnce; currentChild++) {
forkChild(currentChild);
}
// # This sections runs immediately before death of any child is reported
// # and starts cleanup processes, thus killing any/all running children
// Completed before timeout
endTimer = true;
int timeRemaining = alarm(0);
if (timeRemaining > 0) {
printf("\nCompleted w/ %is remaining. Performing cleanup.\n", timeRemaining);
// Kill children any running child processes, cleanup
cleanup();
}
return 0;
}
void forkChild(currentChild) {
pid_t pid = fork();
if (pid < 0) {
// Error
} else if (pid == 0) {
// Child
execl("/bin/date", "date", 0, 0);
} else {
// Parent
printf("#Log: Started %i.\n", currentChild + 1);
}
}
void catchChild(int sig) {
pid_t p;
int state;
p=wait(&state);
printf("Got child %d\n",p);
}
void cleanup() {
// Cleanup Code
}
Example Run:
Edit #2: http://ideone.com/noUs3m
Instead of using wait
as you have done, you want to look into signal handling to handle the child processes dying.
You add before you start fork
ing, this line
signal(SIGCHLD,catchchild);
and this function to your code
void catchchild(int sig)
{
pid_t p;
int state;
p=wait(&state);
printf("Got child %d\n",p);
}
and then whenever a child process dies, your main process will call catchchild
.
As you've already worked out, if you have a count of how many children that have been forked, you could have catchchild
update that so that your main code will know to fork
a new child.
To answer your comment something like the following, except with more error checking
while(totalProcessesToBeForked)
{
if(currentChild < maxAllowedAtOnce)
{
forkChild(currentChild);
totalProcessesToBeForked--;
}
sleep(1);
}