0

我正在为需要执行一些子进程并读取它们的输出的工具包编写一个模块。但是,使用该工具包的主程序也可能会产生一些子进程并设置一个信号处理程序,SIGCHLD为其调用wait(NULL)以摆脱僵尸进程。因此,如果我在 mywaitpid()中创建的子进程 exit ,则在调用信号处理程序之前处理子进程,因此wait()信号处理程序中的 in 将等待下一个进程结束(这可能需要永远)。这种行为在waitpid 的手册页中进行了描述(参见被授权者 2),因为 linux 实现似乎不允许该wait()家族处理SIGCHLD. 我已经尝试popen()posix_spawn()他们都有同样的问题。我也尝试过使用 doublefork()以便直接子级立即存在,但我仍然无法收到waitpid()调用后SIGCHLD的 garentee。

我的问题是,如果程序的其他部分设置了一个调用的信号处理程序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;
}
4

1 回答 1

0

如果进程是单线程的,可以暂时阻塞 CHLD 信号(使用 sigprocmask),fork/waitpid,然后再次解除阻塞。

不要忘记在分叉子进程中取消阻塞信号 - 尽管 POSIX 声明在进程启动时信号掩码是未定义的,但大多数现有程序都希望它完全未设置。

于 2015-01-17T20:41:12.943 回答