我正在为一个工具包编写一个模块,它需要执行一些子进程并读取它们的输出。但是,使用该工具包的主程序也可能产生一些子进程并为SIGCHLD
设置一个信号处理程序,它调用wait(NULL)
来摆脱僵尸进程。因此,如果子进程在我的waitpid()
内创建退出,则在调用信号处理程序之前处理子进程,因此信号处理程序中的wait()
将等待下一个进程结束(这可能需要永远)。这种行为在the man page of waitpid中描述(请参阅受助者2),因为linux实现似乎不允许wait()
系列处理SIGCHLD
。我尝试了popen()
和posix_spawn()
,但他们都遇到了同样的问题。我还尝试使用双fork()
,以便直接存在子项,但我仍然无法保证在waitpid()
收到后调用SIGCHLD
。
我的问题是,如果程序的其他部分设置了一个调用wait()
的信号处理程序(也许它应该调用waidpid
,但这不是我能控制的),有没有办法安全地执行子进程而不覆盖SIGCHLD
处理程序(因为它可能在某些程序中有用)或任何僵尸进程。
一个显示问题的小程序在这里(注意主程序只在长时间子进程退出后退出,而不是短进程,它直接等待waitpid()):
#include <signal.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
static void
signalHandler(int sig)
{
printf("%s: %d\n", __func__, sig);
int status;
int ret = waitpid(-1, &status, 0);
printf("%s, ret: %d, status: %d\n", __func__, ret, status);
}
int
main()
{
struct sigaction sig_act;
memset(&sig_act, 0, sizeof(sig_act));
sig_act.sa_handler = signalHandler;
sigaction(SIGCHLD, &sig_act, NULL);
if (!fork()) {
sleep(20);
printf("%s: long run child %d exit.\n", __func__, getpid());
_exit(0);
}
pid_t pid = fork();
if (!pid) {
sleep(4);
printf("%s: %d exit.\n", __func__, getpid());
_exit(0);
}
printf("%s: %d -> %d\n", __func__, getpid(), pid);
sleep(1);
printf("%s, start waiting for %d\n", __func__, pid);
int status;
int ret = waitpid(pid, &status, 0);
printf("%s, ret: %d, pid: %d, status: %d\n", __func__, ret, pid, status);
return 0;
}
答案 0 :(得分:0)
如果进程是单线程的,您可以暂时阻止CHLD信号(使用sigprocmask),fork / waitpid,然后再次取消阻塞。
不要忘记解除分叉子节点中的信号 - 尽管POSIX声明信号掩码在进程启动时未定义,但大多数现有程序都希望它完全取消设置。