【问题标题】:How to Spawn Child Processes that Don't Die with Parent?如何产生不与父进程一起死亡的子进程?
【发布时间】:2013-07-10 01:29:57
【问题描述】:

我有一个 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++ 编写。

【问题讨论】:

  • 我不认为使用系统是个好主意....
  • 为什么不使用系统是个好主意?除了明显的安全问题?我在一个非常受控的环境中的嵌入式系统上执行此操作,我不担心错误的系统调用。还有其他我应该警惕的原因吗?
  • @zachd1_618 用于安全问题,如果 /bin/sh 不存在,您将遇到某种问题
  • @Alexis 感谢您提供的信息。以后我会小心的,但在这种情况下,系统是封闭和受控的,安全不是问题。

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


【解决方案1】:

https://github.com/w-A-L-L-e/wash/blob/master/src/wash.cpp 中有一个 execvp 示例。传递命令行参数有时是来自 unistd 的 exec* 函数的问题,并且让环境通过可能是一些工作。总之,希望对你有帮助……

【讨论】:

    【解决方案2】:

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

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

    可能会出现许多其他问题,例如继承的 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;
        }
    }
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        你应该避免使用系统。

        不要在带有 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
        ...
        

        【讨论】:

          【解决方案5】:

          尝试在进程名称前使用systemsetsid

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

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

          【讨论】:

            【解决方案6】:

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

            【讨论】:

            • execv 在第二个参数中需要一个 char**
            猜你喜欢
            • 1970-01-01
            • 2014-06-19
            • 1970-01-01
            • 1970-01-01
            • 2018-02-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多