如何生成不会随父级一起死亡的子进程?

How to Spawn Child Processes that Don't Die with Parent?

本文关键字:子进程 一起 何生成      更新时间:2023-10-16

我有一个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++写这篇文章。

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

两个重要的概念是setsid()和doublefork()。这两者的结合可以防止在孤儿完成时创建僵尸,也可以防止在父对象完成时杀死孤儿。

可能会出现许多其他问题,如继承的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 FAILEDn"); return pid; }
    if (pid == 0) { // CHILD
        setsid(); // Make this process the session leader of a new session
        pid = fork();
        if (pid < 0) { printf("FORK FAILEDn"); 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 orphann");
        return -1;
    }
}

不要使用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
}

您应该避免使用系统。

不要从具有设置用户ID或设置组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
...

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

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

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

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

您应该阅读高级Linux编程了解更多信息。

中有一个execvp示例https://github.com/w-A-L-L-e/wash/blob/master/src/wash.cpp.传递命令行参数有时是unistd的exec*函数的问题,而传递环境可能需要一些工作。不管怎样,希望它能帮助。。。