Sunday, December 13, 2015

Running a stand alone child process from a parent process

Sometimes it is necessary to start a process from within another process, whether it is for executing a command line utility or to create a peer process with which the parent process will need to communicate.

In order to create a stand alone process, that is not tied to the life cycle of the parent process, please read this article. Basically, to detach from the parent process, the child process needs to call setsid. This way, the child will survive after the parent's termination.

Coming back to the topic of the article, there are three ways of starting a separate process under linux:

1) Using system()

//parent process

#include <stdlib.h>

int main(int argc, const char** argv)
{
    system("myapplication");

    //do stuff in parent
}

//child process (myapplication)

#include <unistd.h>

int main ()
{
    pid_t cpid;

    //child process needs to detach from parent in case of blocking system() call
    cpid = fork();
    if (cpid == -1){
        printf("fork error\n");
        exit(1);
    }
    if(cpid > 0){
        exit(0); //parent exits
    }
    
    setsid();

    //do stuff in child
}
Since system() is a blocking call, we need to detach from the parent process in the child - hence the forking in the child process code.

2) Using the classical fork() in the parent process, followed by execv()

//parent process

#include <stdlib.h>
#include <unistd.h>

int main(int argc, const char** argv)
{
    pid_t cpid = fork();
    if (cpid == -1){
        printf("fork error\n");
        exit(1);
    }
    if(cpid == 0){
        execv("myapplication", NULL);
        exit(0);
    }

    //do stuff in parent
}

//child process (myapplication)

#include <unistd.h>

int main ()
{
    setsid();

    //do stuff in child
}
As we are forking in the parent process, it is no longer necessary to fork in the child process also. A call to setsid() is necessary though in order for the child to outlive the parent.
A downside to this approach is that we are forking (copying process state) the whole parent process (which can be quite big in memory occupied) in order to replace it's executing image with another process.

3) Using posix_spawn()

//parent process

#include <spawn.h>

int main(int argc, const char** argv)
{
    char *argV[] = {"myapplication", (char *) 0};
    pid_t pid;
    int status = -1;
    status = posix_spawn(&pid, "myapplication", NULL, NULL, argV, NULL);
    if(status != 0){
         exit(1);
    }

    //do stuff in parent
}

//child process (myapplication)

#include <unistd.h>

int main ()
{
    setsid();

    //do stuff in child
}
Using posix_spawn() seems the most efficient way to go with spawning a new process. Forking in the child in order to detach is not necessary, just detaching with a setsid() call.

No comments:

Post a Comment