为什么"X"可以是输出的最后一个字符?

Why can "X" be the last character of output?

#include <stdio.h>
#include <sys/types.h> 
#include <sys/wait.h> 
#include <sys/types.h>
#include <unistd.h>

int main() {
    if (fork() == fork()){

        fprintf(stderr, "Z");
    }
    else {
        if (waitpid((pid_t)-1,NULL,0)!=-1) {
            fprintf(stderr, "Y");

        }
        else {
            fprintf(stderr, "X");
        }
    }
}

我正在研究这个程序,我发现 "ZYYX" 可以是输出。我不太明白为什么。在我的理解中,一共有四个过程,parent->parent,parent->child,child->parent,child->parent。毫无疑问,child->child 打印 Z。child->parent 在 child->child 打印 Z 之后打印 Y。parent->parent 应该等到 parent->child 打印 X。那么为什么 X 可能是打印为输出的最后一个字符?

我意识到 waitpid 等待任何子进程,所以如果 ZY 已经打印出来,那么 Y 可以立即打印出来,因为它已经等待 "Y"。因此,X 可以打印为最后一个字符。

我想我以前没有在代码中看到过 if (fork() == fork()) — 恭喜!我不完全相信你的追踪;我希望看到每个进程的 PID 包含在它所做的任何打印中,并且我希望在每个输出的末尾有一个换行符。另外,原代码中至少有一个进程未等待

这是一个重写,它报告执行每个打印操作的进程的 PID。一些进程以 non-zero 状态退出,主要是为了让它在输出中更有趣一些。该代码跟踪检测到的尸体并报告其状态。它还引入了一个循环来清理死children。原始进程有一个 child,否则不会被清理。

#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void)
{
    if (fork() == fork())
    {
        fprintf(stderr, "Z(%d)\n", (int)getpid());
        return 23;
    }
    else
    {
        int corpse;
        int status;
        if ((corpse = waitpid((pid_t)-1, &status, 0)) != -1)
            fprintf(stderr, "Y(%d) - PID %d 0x%.4X\n", (int)getpid(), corpse, status);
        else
        {
            fprintf(stderr, "X(%d)\n", (int)getpid());
            return 37;
        }
        while ((corpse = waitpid((pid_t)-1, &status, 0)) != -1)
            fprintf(stderr, "Q(%d) - PID %d 0x%.4X\n", (int)getpid(), corpse, status);
    }
    return 0;
}

示例输出:

X(16551)
Y(16547) - PID 16551 0x2500
Z(16552)
Y(16550) - PID 16552 0x1700
Q(16547) - PID 16550 0x0000

如你所见,将有 4 个进程,基于两个 fork,每个进程将打印一个字母:

1st fork  2nd fork    prints                   PP
parent    parent        Y                     /  \
parent    child         X                   CP    PC
child     parent        Y                    \
child     child         Z                     CC

左边的图表显示了 parent/child 关系——/ 是第一个分支,\ 是第二个分支。

所以 CC 打印 Z 因为两个 fork return 0,而 PC 打印 X。另外两个都等待 child 退出,然后打印 Y。在CP的cas中,只有一个child,所以Y永远在Z之后,但是PP有两个childre,所以Y 可能在 ZY 之后或 X 之后。两者皆有可能。所以你可以获得任何

XYZY   PC,PP,CC,CP
XZYY   PC,CC,PP,CP or PC,CC,CP,PP
ZXYY   CC,PC,PP,CP or CC,PC,CP,PP
ZYXY   CC,CP,PC,PP
ZYYX   CC,CP,PP,PC