我有一个C ++程序,可以作为其他人的监督者。如果它检测到某个进程不再运行,则会通过system
重新启动它。问题是,如果我杀死看门狗进程,它启动的任何进程也会死掉。
void* ProcessWatchdog::worker(void* arg)
{
//Check if process is running
if( !processRunning )
system("processName /path/to/processConfig.xml &");
}
新的子进程正确启动,并且运行没有任何问题。但是当父母(现在这个ProcessWatchdog
过程)死亡时,孩子也会死亡。如何生成完全独立于父级的子进程?
我尝试过使用pclose
和popen
,运行启动进程的shell脚本以及其他一些策略,但无济于事。我忽略了子进程中的SIGHUP
信号,但它们仍然死亡。
理想情况下,我想告诉系统启动一个完全独立于父级的进程。我希望孩子的trace
以孩子结束,并且系统根本不知道ProcessWatchdog
首先启动了它。
我有办法做到这一点吗?
我在Linux上用C ++编写这个。
答案 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)
尝试在流程名称之前使用system
和setsid
。
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 *函数的问题,并且获得传递的环境可能是一些工作。无论如何,希望它有所帮助...