我正在尝试创建一个管理其他进程的进程,如果一个子进程死掉,那么父进程将重新启动进程和依赖它的进程。
问题是我注意到,如果我在此结构中间重新启动进程时创建进程的树结构,则在新的子进程终止时无法发出信号。
我写了一个例子;假设我们有3个过程,祖父母,父母和孩子。 祖父母分叉并启动父分叉并启动子代(我把代码放在这篇文章的末尾)。现在,如果我杀了孩子一切正常,孩子会正确重启。
如果我杀死父级,则会出现问题...祖父母重新启动父级重新启动子级,但是如果我杀死子级,则该进程将保持在Zombie状态,并且SIGCHLD不会传递给父进程。
换句话说:
我无法理解这种行为......我已经阅读了大量有关信号和等待的示例和文档,尝试在父级和祖父级中的fork之前重置默认处理程序,但似乎没有任何工作...... 这是代码示例......
grandparent.cpp
#include <cstdio>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <signal.h>
#include <wait.h>
using namespace std;
void startProcess(string processFile);
void childDieHandler(int sig, siginfo_t *child_info, void *context);
FILE *logFile;
int currentChildPid;
int main(int argc, char** argv)
{
currentChildPid = 0;
logFile = stdout;
daemon(1,1);
struct sigaction sa;
bzero(&sa, sizeof(sa));
sa.sa_sigaction = childDieHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sigaction(SIGCHLD, &sa, NULL);
startProcess("parent");
while(true) {
sleep(60);
}
return 0;
}
void startProcess(string processFile)
{
fprintf(logFile, "\nGP:Starting new process %s\n",processFile.c_str());
// Get process field and start a new process via fork + execl
int pid = fork();
if (pid == -1){
fprintf(logFile,"GP:*** FORK ERROR on process %s !!!\n",processFile.c_str());
fflush(logFile);
return;
}
// New child process
if (pid == 0) {
string execString = get_current_dir_name()+(string)"/"+processFile;
fprintf(logFile, "GP: %s \n",execString.c_str());
execl(execString.c_str(), processFile.c_str(), NULL);
fprintf(logFile, "GP:*** ERROR on execv for process %s\n",processFile.c_str());
fflush(logFile);
exit(1);
} else {
// Parent process
fprintf(logFile, "GP:New process %s pid is %d .\n", processFile.c_str(), pid);
fflush(logFile);
currentChildPid = pid;
sleep(2);
}
}
// Intercept a signal SIGCHLD
void childDieHandler(int sig, siginfo_t *child_info, void *context){
int status;
pid_t childPid;
while((childPid = waitpid(-1,&status, WNOHANG)) > 0) {
int pid = (int) childPid;
fprintf(logFile,"GP:*** PROCESS KILLED [pid %d]\n",pid);
sigset_t set;
sigpending(&set);
if(sigismember(&set, SIGCHLD)){
fprintf(logFile, "GP: SIGCHLD is pending or blocked!!!!\n");
fflush(logFile);
}
fflush(logFile);
// identify exited process and then restart it
if(currentChildPid == childPid){
// kill any child
system("killall child");
fprintf(logFile,"GP: Restarting parent process...\n");
fflush(logFile);
startProcess("parent");
}
}
fprintf(logFile,"GP:End of childDieHandler()... [%d]\n\n",(int)childPid);
fflush(logFile);
}
parent.cpp
#include <cstdio>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <signal.h>
#include <wait.h>
using namespace std;
void startProcess(string processFile);
void childDieHandler(int sig, siginfo_t *child_info, void *context);
FILE *logFile;
int currentChildPid;
int main(int argc, char** argv)
{
currentChildPid = 0;
logFile = stdout;
struct sigaction sa;
bzero(&sa, sizeof(sa));
sa.sa_sigaction = childDieHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sigaction(SIGCHLD, &sa, NULL);
startProcess("child");
while(true) {
sleep(60);
}
return 0;
}
void startProcess(string processFile)
{
fprintf(logFile, "\nP : Starting new process %s\n",processFile.c_str());
// Get process field and start a new process via fork + execl
int pid = fork();
if (pid == -1){
fprintf(logFile,"P : *** FORK ERROR on process %s !!!\n",processFile.c_str());
fflush(logFile);
return;
}
// New child process
if (pid == 0) {
string execString = get_current_dir_name()+(string)"/"+processFile;
execl(execString.c_str(), processFile.c_str(), NULL);
fprintf(logFile, "P : *** ERROR on execv for process %s\n",processFile.c_str());
fflush(logFile);
exit(1);
} else {
// Parent process
fprintf(logFile, "P : New process %s pid is %d .\n", processFile.c_str(), pid);
fflush(logFile);
currentChildPid = pid;
sleep(2);
}
}
// Intercept a signal SIGCHLD
void childDieHandler(int sig, siginfo_t *child_info, void *context){
int status;
pid_t childPid;
while((childPid = waitpid(-1,&status, WNOHANG)) > 0) {
int pid = (int) childPid;
fprintf(logFile,"P : *** PROCESS KILLED [pid %d]\n",pid);
sigset_t set;
sigpending(&set);
if(sigismember(&set, SIGCHLD)){
fprintf(logFile, "P : SIGCHLD is pending or blocked!!!!\n");
fflush(logFile);
}
fflush(logFile);
// identify exited process and then restart it
if(currentChildPid == childPid){
fprintf(logFile,"P : Restarting child process...\n");
fflush(logFile);
startProcess("child");
}
}
fprintf(logFile,"P : End of childDieHandler()... [%d]\n\n",(int)childPid);
fflush(logFile);
}
child.cpp
#include <cstdio>
#include <string>
#include <cstring>
int main(int argc, char** argv)
{
printf("\nC : I'm born...\n\n");
while(true) {
sleep(60);
}
return 0;
}
答案 0 :(得分:2)
嗯,我有猜测......
在信号处理程序内部,SIGCHLD
信号被阻止(即,它是进程信号掩码的成员)。
因此,当祖父母从信号处理程序内部调用execl
时,新父母将以SIGCHLD
阻止启动。因此,它永远不会看到信号,也永远不会等待新的孩子。
尝试在parent.cpp的开头调用sigprocmask
,以便(a)验证此理论并(b)取消阻止SIGCHLD。