gpt4 book ai didi

linux - SIGCHLD 未在进程树中传递

转载 作者:太空狗 更新时间:2023-10-29 12:21:12 27 4
gpt4 key购买 nike

我正在尝试创建一个管理其他进程的进程,如果一个 child 死了,那么 parent 会重新启动该进程以及依赖于它的进程。

问题是我注意到,如果我在这个结构的中间重新启动一个进程时创建了一个进程的树结构,那么当新的子进程终止时我无法收到信号。

我写了一个例子;假设我们有 3 个进程,祖 parent 、 parent 和 child 。祖 parent fork 并开始 parent fork 并开始 child (我把代码放在这篇文章的末尾)。现在,如果我杀死 child ,一切正常, child 会正确重启。

如果我杀死父进程就会出现问题...祖 parent 重启父进程并重启子进程,但是如果我杀死子进程,进程将保持僵尸状态并且 SIGCHLD 不会传递给父进程。

换句话说:

  • 启动祖父进程并等待所有 3 个进程都启动
  • 杀死父进程并等待祖 parent 重启父进程并重启子进程
  • 现在杀死子进程,进程保持僵尸状态。

我无法理解这种行为......我已经阅读了大量关于信号和等待的示例和文档,尝试在父和祖 parent 的 fork 之前重置默认处理程序,但似乎没有任何效果......这是代码示例...

祖 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;

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);
}

父类.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;
}

最佳答案

嗯,我有一个猜测......

在信号处理程序中,SIGCHLD 信号被阻塞(即,它是进程信号掩码的成员)。

因此,当祖 parent 从信号处理程序内部调用 execl 时,新 parent 启动时 SIGCHLD 被阻止。因此它永远不会看到信号,也永远不会等待新的 child 。

尝试在 parent.cpp 的开头调用 sigprocmask 以 (a) 验证该理论和 (b) 解锁 SIGCHLD。

关于linux - SIGCHLD 未在进程树中传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7637049/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com