如何产生不与父亲一起死亡的儿童过程?

时间:2013-07-11 16:49:00

标签: c++ linux fork parent-child spawn

我有一个C ++程序,可以作为其他人的监督者。如果它检测到某个进程不再运行,则会通过system重新启动它。问题是,如果我杀死看门狗进程,它启动的任何进程也会死掉。

void* ProcessWatchdog::worker(void* arg)
{
    //Check if process is running
    if( !processRunning )
        system("processName /path/to/processConfig.xml &");
}

新的子进程正确启动,并且运行没有任何问题。但是当父母(现在这个ProcessWatchdog过程)死亡时,孩子也会死亡。如何生成完全独立于父级的子进程?

我尝试过使用pclosepopen,运行启动进程的shell脚本以及其他一些策略,但无济于事。我忽略了子进程中的SIGHUP信号,但它们仍然死亡。

理想情况下,我想告诉系统启动一个完全独立于父级的进程。我希望孩子的trace以孩子结束,并且系统根本不知道ProcessWatchdog首先启动了它。

我有办法做到这一点吗?

我在Linux上用C ++编写这个。

6 个答案:

答案 0 :(得分:4)

这个有点旧但没有得到完整的答案。以下是我在嵌入式系统上所做的,以生成与父级无关的bash子级。请注意,我执行了一个bash shell,然后在另一个bash shell中运行我的命令。在您的情况下,这可能不是必需的。对我来说,它允许我进行一些没有它就无法正常工作的I / O重定向。

两个重要的概念是setsid()和double fork()。这两者的组合可以防止在孤儿完成时创建僵尸,并防止孤儿在父母完成时被杀死。

还有许多其他问题可能出现,例如继承的I / O句柄,工作目录等,但这段代码完成了基本工作。

int spawn_orphan(char* cmd) {
    char command[1024]; // We could segfault if cmd is longer than 1000 bytes or so
    int pid;
    int Stat;
    pid = fork();
    if (pid < 0) { perror("FORK FAILED\n"); return pid; }
    if (pid == 0) { // CHILD
        setsid(); // Make this process the session leader of a new session
        pid = fork();
        if (pid < 0) { printf("FORK FAILED\n"); exit(1); }
        if (pid == 0) { // GRANDCHILD
            sprintf(command,"bash -c '%s'",cmd);
            execl("/bin/bash", "bash", "-c", command, NULL); // Only returns on error
            perror("execl failed");
            exit(1);
        }
        exit(0); // SUCCESS (This child is reaped below with waitpid())
    }

    // Reap the child, leaving the grandchild to be inherited by init
    waitpid(pid, &Stat, 0);
    if ( WIFEXITED(Stat) && (WEXITSTATUS(Stat) == 0) ) {
        return 0; // Child forked and exited successfully
    }
    else {
        perror("failed to spawn orphan\n");
        return -1;
    }
}

答案 1 :(得分:3)

不要使用system(...)它不是多线程安全的。

int pid = fork();

if(pid==0)
{
  int rc = execv("processname", "/path/to/processConfig.xml &");
  if(rc == -1)
  {
    printf(stderr, "processname failed to start. %d", errno);
  }
  ...
}
else
{
  //continue with the parent
}

答案 2 :(得分:1)

你应该避免使用系统。

  

请勿使用set-user-ID或set-group-ID的程序中的system()          特权,因为某些环境变量的奇怪值          可能会被用来破坏系统的完整性。使用exec(3)系列          而不是功能。

以及如果您想检查返回值或其他任何内容

选择execl

#include <unistd.h>
#include <stdlib.h>
pid_t pid = fork()
if (pid == -1)
{
   exit(EXIT_FAILURE);
}
else if (pid == 0)
{
  if (execl("processname", "processname", "/path/to/processConfig.xml", NULL) == -1)
    exit(EXIT_FAILURE); 
}
else
...

答案 3 :(得分:0)

尝试在流程名称之前使用systemsetsid

system("setsid processname /path/to/processConfig.xml &");

这将在新会话中启动该程序。

答案 4 :(得分:0)

您可能对daemon(3)库函数感兴趣(内部使用两个嵌套的fork(2)系统调用)。之后,使用相关的execve(2)系统调用(或相关的exec(3)函数)......

您应该阅读Advanced Linux Programming了解更多信息。

答案 5 :(得分:0)

https://github.com/w-A-L-L-e/wash/blob/master/src/wash.cpp中有一个execvp示例。传递命令行参数有时是来自unistd的exec *函数的问题,并且获得传递的环境可能是一些工作。无论如何,希望它有所帮助...