6

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

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

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

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

所以理想情况下,我想告诉系统启动一个完全独立于父进程的进程。我希望孩子trace以孩子结束,并且让它/系统不知道它ProcessWatchdog一开始就开始了。

有没有办法我可以做到这一点?

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

4

6 回答 6

5

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

两个重要的概念是 setsid() 和双 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;
    }
}
于 2014-02-28T01:19:54.840 回答
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
}
于 2013-07-11T17:06:18.660 回答
2

你应该避免使用系统。

不要在具有 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
...
于 2013-07-11T17:19:48.610 回答
1

尝试在进程名称前使用systemwith 。setsid

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

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

于 2013-07-11T17:13:42.937 回答
0

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

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

于 2013-07-11T20:20:15.963 回答
0

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

于 2015-03-16T12:40:31.293 回答