waitpid是否为已经退出的子进程提供有效的状态信息?

8
如果我使用fork创建了一个子进程,并且在父进程调用waitpid之前子进程退出,那么由waitpid设置的退出状态信息是否仍然有效?如果有效,那么它何时变为无效;即,我如何确保可以在任意时间后调用waitpid获取子进程的有效退出状态信息,并如何“清理”(告诉操作系统我不再对已完成的子进程的退出状态信息感兴趣)?
我正在尝试以下代码,似乎子进程完成后的退出状态信息至少在几秒钟内是有效的,但我不知道有效时间有多长,也不知道如何通知操作系统我不会再次调用waitpid
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
    pid_t pid = fork();

    if (pid < 0) {
        fprintf(stderr, "Failed to fork\n");
        return EXIT_FAILURE;
    }
    else if (pid == 0) { // code for child process
        _exit(17);
    }
    else { // code for parent
        sleep(3);

        int status;
        waitpid(pid, &status, 0);
        waitpid(pid, &status, 0); // call `waitpid` again just to see if the first call had an effect
        assert(WIFEXITED(status));
        assert(WEXITSTATUS(status) == 17);
    }

    return EXIT_SUCCESS;
}
3个回答

14

是的,在子进程退出后,waitpid 仍然可以工作。操作系统会在进程表中保留子进程的条目(包括退出状态),直到父进程调用 waitpid(或另一个 wait 系列函数)或者父进程退出时才将其清除(此时状态由 init 进程收集)。这就是所谓的“僵尸”进程:已经退出但在进程表中仍然存在的进程,正是为了这个目的。

第一次调用 waitpid 后,进程在表中的条目应该会消失。我怀疑你的例子中之所以能够连续调用两次 waitpid 的原因只是因为如果 pid 不再存在,waitpid 不会修改 status 参数。因此,第一次调用应该可以正常工作并填充 status,而第二次调用应该会返回错误代码并且不改变 status。您可以通过检查 waitpid 调用的返回值和/或使用两个不同的 status 变量来验证这一点。


确实,第二个waitpid调用失败了。我没有考虑到这一点!谢谢你指出来。 - Daniel Trebbien

3
操作系统会将已终止的进程保持在僵尸状态,直到其父进程(如果原始父进程早先终止,则可能是init)使用wait(2)系统调用收集该退出状态。因此,答案是 - 进程的退出状态不会变为无效

2

是的。

man页面

一个终止但未被等待的子进程成为“僵尸”。 内核维护有关僵尸进程的最少信息 (PID,终止状态,资源使用信息), 以便允许父进程稍后执行等待操作 以获取有关子进程的信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接