Search code examples
cfork

Proper Way to Fork Process


I'm trying to send a request to a server, and fork it each time beforehand:

int main(void)
{
    // request send
    fork();
// errx() error handling
    return 0;
}

This however only causes 1 fork, then the program crashes. I've been browsing through some docs online and cannot figure out what I'm doing wrong and why it isn't forking each time it attempts to query a server.


Solution

  • Your main problem is execution path. Both parent and child process continue to errx, which apparently kills the active process, meaning no iterations in the parent or child. You don't check the result of fork, which is purposely there to help you tell if the function (a) worked, and (b) the current process is the parent or just-forked child.

    You're better off setting up the parent process to be a watchdog, and launching the child processes to be guarded. A simple shell example is below, which sequentially launches child processes, waiting for each to terminate.

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main()
    {
        for (int i=0; i<10; ++i)
        {
            pid_t pid = fork();
            if (pid == 0)
            {
                // handle child process here
                sleep(1);
                return EXIT_SUCCESS;
            }
    
            if (pid < 0)
            {
                perror("Failed to launch child process");
                exit(EXIT_FAILURE);
            }
            else
            {
                printf("child %d started\n", (int)pid);
                int res = 0;
                pid = wait(&res);
                printf("child %d exited, result = %d\n", (int)pid, WEXITSTATUS(res));
            }
    
        }
        return EXIT_SUCCESS;
    }
    

    Example Output

    child 72916 started
    child 72916 exited, result = 0
    child 72917 started
    child 72917 exited, result = 0
    child 72919 started
    child 72919 exited, result = 0
    child 72920 started
    child 72920 exited, result = 0
    child 72921 started
    child 72921 exited, result = 0
    child 72923 started
    child 72923 exited, result = 0
    child 72924 started
    child 72924 exited, result = 0
    child 72925 started
    child 72925 exited, result = 0
    child 72926 started
    child 72926 exited, result = 0
    child 72927 started
    child 72927 exited, result = 0
    

    Monitoring Batches

    For a more complicated version, the following launches child processes in batches of three, then waits for all three to terminate before launching the next batch. This is repeated three times for a total of nine processes total (ten, including the parent watchdog).

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main()
    {
        for (int i=0; i<3; ++i)
        {
            // batch launch loop
            int n_children = 3;
            for (int j=0; j<3; ++j)
            {
                pid_t pid = fork();
                if (pid == 0)
                {
                    // handle child process here
                    sleep(1);
                    return EXIT_SUCCESS;
                }
                else if (pid < 0)
                {
                    perror("Failed to launch child process");
                    --n_children;
                }
                else
                {
                    printf("child %d started\n", (int)pid);
                }
            }
    
            // batch wait loop
            for (int j=0; j<n_children; ++j)
            {
                int res;
                pid_t pid = wait(&res);
                printf("child %d exited, result = %d\n", (int)pid, WEXITSTATUS(res));
            }
        }
        return EXIT_SUCCESS;
    }
    

    Example Output

    child 73190 started
    child 73191 started
    child 73192 started
    child 73190 exited, result = 0
    child 73191 exited, result = 0
    child 73192 exited, result = 0
    child 73193 started
    child 73194 started
    child 73195 started
    child 73194 exited, result = 0
    child 73193 exited, result = 0
    child 73195 exited, result = 0
    child 73196 started
    child 73197 started
    child 73198 started
    child 73196 exited, result = 0
    child 73197 exited, result = 0
    child 73198 exited, result = 0
    

    Hopefully you'll find some of that helpful.