fork()在进程执行结束后输出什么?

4

考虑下面的代码片段:

int main()
{
    fork();
    fork();
    fork();
    printf("Hello World\n");
}

我得到的输出是:[ubuntu 12.04]
aashish@aashish-laptop:~$ ./a.out
Hello World
Hello World
Hello World
aashish@aashish-laptop:~$ Hello World <---------------------------
Hello World
Hello World
Hello World
Hello World

为什么“Hello World”会在进程执行结束后输出?

3
可能是因为当那个进程退出时,仍有从fork运行的另一个进程在输出。 - Alex W
SO 上这个问题的重复太多了...每天都有... - user529758
3
严格来说,fork() 并不会输出任何内容。当然,由 fork() 创建的各个子进程在退出之前会输出一行信息。有时候,顶级进程(初始进程)会在它的某些子进程之前完成,所以这些子进程会在 shell 写出下一个命令提示符之后再输出它们的信息。如果你希望父进程等待(使用 waitpid()wait())直到它的子进程死亡后再退出,你需要编写相应的代码。在输出的信息中包括 PID (getpid()) 会有助于你了解正在发生的事情。 - Jonathan Leffler
4个回答

5
简短的回答是您正在创建多个进程,它们异步运行。长答案如下:
当您在shell提示符处键入`./a.out`时,会创建一个运行您程序的进程。我们将其称为进程1。
进程1调用fork()。这会创建一个新的子进程2,第一次fork()呼叫后,1和2继续执行,并继续执行第二次fork()呼叫。进程1创建子进程3,进程2创建子进程4。所有四个进程都从第二个fork()之后继续执行,并进行最后的fork()呼叫。进程1创建Process 5;进程2创建Process 6;进程3创建Process 7;进程4创建Process 8。
请注意,这些进程编号是任意的:无法保证它们按该顺序创建。
异步性在第一次fork()被执行时就发挥作用。系统不保证父进程与子进程的调度关系。理论上,子进程可能在父进程之前完成,父进程可能在子进程获得任何资源之前完成。最可能的情况在两者之间:原始进程与其后代共享资源,以使所有进程同时运行。
谜题的最后一块拼图结果来自于shell正在等待进程1完成。只有进程1。shell不知道(或不关心)进程1已经启动了其他进程。因此,当进程1完成时,shell会显示提示符。恰好,进程1的某些后代尚未达到printf()语句。当它们到达那里时,shell已经显示了其提示符。
要进一步探索这个问题,您可能需要尝试将fork()呼叫更改为printf("%d\n", fork());和/或将printf("Hello World\n")更改为printf("Hello from pid %d\n", getpid())。

3

第二个shell提示符后面的“Hello World”输出来自分叉的进程,而不是由shell(你)启动的进程。


0
int main() {
    pid_t c[3];
    int i, n = 0;
    for (i = 0; i < 3; ++i) {
        switch ((c[n] = fork())) {
        case 0:  break;
        case -1: perror("fork"); exit(EXIT_FAILURE);
        default: ++n;
        }
    }
    printf("[%d] Hello World\n", (int)getpid());
    // Without waiting, some children may still be running when the
    // parent exits. This makes it look like output is generated
    // after the process is over, when in fact not all the processes
    // are done yet.
    //
    // The process is not really finished until its children are
    // finished. The wait call waits on a child process to finish.
    for (i = 0; i < n; ++i) wait(0);
    return 0;
}

0

这是因为你创建了1个分支(2),然后再次分支(4),然后再次(8),然后对于每个分支打印Hello world。这就是为什么你得到了8个输出的原因。


你的答案在某种程度上是准确的,但它没有解释为什么一些输出会出现在初始进程退出之后,而且外壳程序已经写入了下一个提示符。 - Jonathan Leffler

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