Home > database >  How to correctly terminate processes created with fork() without waiting for their result
How to correctly terminate processes created with fork() without waiting for their result

Time:06-07

According to the task, the program must create a copy of itself using fork () to process the task. Parent process must not be blocked while the child is running.

However, I encountered strange behavior of the test program. According to the result of pgrep, child processes are not terminated until the parent program has completed its execution. Each time fork() is called, pgrep shows that the number of processes is increasing, but they are not terminating.

I wrote a simple program that runs for nearly 35 seconds and spawns a child process 3 times, which should exit after 5 seconds:

#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
    for (int i = 1; i < 36; i  ) {
        if (i % 10 == 0) {
            pid_t forkrank = fork();            
            if (forkrank == 0) {
                printf("forked process starts\n");
                sleep(5);
                return 1;
            }
        }
        sleep(1);
    }
    return 0;
}

But during its execution, pgrep shows that running processes are not terminated until parent ends: pgrep's result

But if I add a blocking code to wait for the result of the child process execution, then additional processes are terminated correctly:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char* argv[])
{
    for (int i = 1; i < 36; i  ) {
        if (i % 10 == 0) {
            pid_t forkrank = fork();
            if (forkrank == 0) {
                printf("forked process starts\n");
                sleep(5);
                return 1;
            }
            int wstatus;
            waitpid(forkrank, &wstatus, 0);
            int retValue = WEXITSTATUS(wstatus);
        }
        sleep(1);
    }
    return 0;
}

pgrep:

pgrep's result ok

Why is this happening? How to terminate child processes without blocking the main one?

CodePudding user response:

You could do a non-blocking wait. This is done by passing the WNOHANG flag as the third parameter to waitpid. You can also pass -1 for the first argument to allow the parent to wait for any pid. You would then put the call to waitpid after the call to sleep in the main loop.

#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
    for (int i = 1; i < 36; i  ) {
        if (i % 10 == 0) {
            pid_t forkrank = fork();            
            if (forkrank == 0) {
                printf("forked process starts\n");
                sleep(5);
                return 1;
            }
        }
        sleep(1);
        waitpid(-1, NULL, WNOHANG);
    }
    return 0;
}

CodePudding user response:

The proper term is reaping the children.

This is done using wait/waitpid. The earlier answer shows how to do this using polling, which requires changing your program to periodically call waitpid. But it's also possible to do without making such changes.

To automatically reap the children as they exit, use sigaction to install a SIGCHLD handler which calls waitpid(-1, NULL, WNOHANG) until it returns a 0 or -1.

This has a side-effect. Blocking system calls can now fail with error EINTR unless you have them automatically restarted.


You could also daemonize the child, making it completely independent of the parent process. The process causes them to become children of init (pid 1), and it automatically reaps terminated children.

CodePudding user response:

You can do that by passing flag WNOHANG as option to wpaitpid See (2): waitpid WNOHANG return immediately if no child has exited.

waitpid(-1, NULL, WNOHANG);
  • Related