【问题标题】:Output from fork() in cc 中 fork() 的输出
【发布时间】:2019-07-17 20:30:20
【问题描述】:

我最近遇到了这段代码,并没有完全理解它。

  1. 什么情况会导致pid == 0?
  2. 为什么 wait(NULL) 会导致程序进入 if(pid == 0)

基本上我不完全理解下面的输出。任何帮助,将不胜感激。谢谢。

代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // standard POSIX header file
#include <sys/wait.h> // POSIX header file for 'wait' function
int main(void)
{
    int i = -1;
    int pid;
    pid = getpid();
    fprintf(stdout, "parent pid = %d\n", pid);
    pid = fork();

    if (pid == 0)
    {
        for (i = 0; i < 10; ++i)
        {
            fprintf(stdout, "child process: %d\n", i);
            sleep(1);
        }
        exit(0);
    }
    else
    {
        fprintf(stdout, "child pid = %d\n", pid);
        fprintf(stdout, "waiting for child\n");
        wait(NULL);
        fprintf(stdout, "child terminated\n");
    }
    fprintf(stdout, "parent terminating\n");
    return 0;
}

输出:

parent pid = 2896
child pid = 5840
waiting for child
child process: 0
child process: 1
child process: 2
child process: 3
child process: 4
child process: 5
child process: 6
child process: 7
child process: 8
child process: 9
child terminated
parent terminating

【问题讨论】:

  • 父进程在fork()之后收到子进程的pid,子进程和父进程都开始并发执行。现在,持有 pid 的父变量拥有孩子的 pid,而孩子中的同一个变量持有 0。
  • 请记住,成功的fork() 会返回两次,分别在两个单独的进程中返回一次。在子(新)进程中,返回值始终为0。在父(旧)进程中,返回值是新(子)进程的PID。如果fork()失败了,那么父进程会得到-1的返回值,就不用担心子进程了。
  • fork 是一个难以理解的函数(甚至难以解释)。你需要花几个小时阅读一些关于它的书籍章节。 ALPOSTEP都是你应该读的书,它们需要几十页来解释fork
  • 你的代码应该调用fflush(3),就像fflush(NULL); 之前 fork
  • wait(NULL),强制父进程等待子进程,直到子进程完成工作。 stackoverflow.com/a/45762189/7508077

标签: c fork posix


【解决方案1】:
  1. fork(2) 系统调用创建了第二个子进程,因此,该调用在父进程中调用一次,但在父进程和子进程中都返回。

    因此,调用之后的代码需要一些指示来知道我们是在父级还是子级中执行代码,因为这允许父级和子级从此时开始转移公共代码。

    fork(2) 的定义在手册页中有说明:

    • 返回-1 并将errno 设置为指示fork(2) 调用失败原因的值。
    • 为子子进程返回0
    • pid_t子进程id返回给父进程(一个正数),这样它就可以知道刚刚启动的新子进程的pid。
  2. wait(NULL);不在if (pid == 0)中,而是在else部分,所以确实在if (pid != 0)或者父进程中。父进程必须知道子进程是否已完成以及如何完成,并且必须与其同步,原因如下:

    • 孩子可以在父母之前exit(2),但是根据孩子的工作量,它可以在父母完成后做。如果父级在子级之前结束,您将再次获得 shell 提示,并且在发出提示后,您的屏幕将因子级的输出而变得模糊。这不是您通常想要的,因此在父级中调用wait(2) 只是出于礼貌,因此 shell 仅在一切完成后才会提示您。

      一个很好的测试是在您的示例中注释 wait(2) 调用,看看会发生什么。

    • wait(2) 系统调用是了解您的孩子如何结束它运行的一种方式(主要是如果您在孩子的进程中exec(2) 某个其他程序)您可以了解您的孩子是否因为它而死亡exit(2) ed(并接收其退出代码),因为它被中断(以及它收到的信号是什么),或者它已被用户/系统出于某种原因停止。

阅读fork(2)exec(2)exit(2)wait(2)系统调用(都作为一组相关调用)将启发所有进程关系以及所有这些系统调用如何协作管理unix进程系统。

【讨论】:

    【解决方案2】:

    正如 Susmit AgrawalJonathan Leffler 在 cmets 中提到的,简要回答您的第一个问题:

    0fork()调用成功返回后子进程内部的返回值。子进程的执行从if (pid == 0) 块开始。它在每次迭代中遍历for循环,printssleeps,最后调用exit(0),子进程终止。

    fork() 调用之后父进程 的执行在else 块中继续。 父进程返回的PID就是子进程的PID

    简单回答你的第二个问题:

    wait(NULL)用于等待子进程状态的变化。在这种特定情况下,状态变化是孩子的终止。参数NULL 只是表示不会存储任何状态信息。

    有关更多详细信息,请阅读链接的手册页。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 2020-05-08
    • 2012-01-12
    • 2012-10-04
    • 1970-01-01
    • 2012-06-23
    相关资源
    最近更新 更多