【问题标题】:I'm trying to make a diagram of fork() process calls in C我正在尝试在 C 中制作 fork() 进程调用图
【发布时间】:2020-09-25 20:02:51
【问题描述】:

这就是我现在的位置

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

main(){   
    int n;
    int i;
    int x = 1;

    printf("\nenter number of forks:\n");
    scanf ("%d",&n);
    printf("\nnow forking %d times....\n\n", n);

    for (i = 1;i <= n; i++){
        int pid = fork();
        if (pid < 0){ 
            return -1;
        }

        if (pid != 0){
            printf("\nI am the parent (
                ppid = %d pid = %d)\n",getppid(),getpid()
            );          
            printf(" x = %d\n",x);

            x++;
            wait();
        }else{
            printf("\nI am the child (
                ppid = %d, pid = %d)\n x = 
                %d\n-------------------------------\n",
                getppid(),getpid(),x
            );
        }
    }
}

这是我传入 4 时的输出:

enter number of forks:
4

now forking 4 times....


I am the parent (ppid = 26178 pid = 39785)
 x = 1

I am the child (ppid = 39785, pid = 39786)
 x = 1
-------------------------------

I am the parent (ppid = 39785 pid = 39786)
 x = 1

I am the child (ppid = 39786, pid = 39787)
 x = 1
-------------------------------

I am the parent (ppid = 39786 pid = 39787)
 x = 1

I am the child (ppid = 39787, pid = 39788)
 x = 1
-------------------------------

I am the parent (ppid = 39787 pid = 39788)
 x = 1

I am the child (ppid = 39788, pid = 39789)
 x = 1
-------------------------------

I am the parent (ppid = 39786 pid = 39787)
 x = 2

I am the child (ppid = 39787, pid = 39790)
 x = 2
-------------------------------

I am the parent (ppid = 39785 pid = 39786)
 x = 2

I am the child (ppid = 39786, pid = 39791)
 x = 2
-------------------------------

I am the parent (ppid = 39786 pid = 39791)
 x = 2

I am the child (ppid = 39791, pid = 39792)
 x = 2
-------------------------------

I am the parent (ppid = 39785 pid = 39786)
 x = 3

I am the child (ppid = 39786, pid = 39793)
 x = 3
-------------------------------

I am the parent (ppid = 26178 pid = 39785)
 x = 2

I am the child (ppid = 39785, pid = 39794)
 x = 2
-------------------------------

I am the parent (ppid = 39785 pid = 39794)
 x = 2

I am the child (ppid = 39794, pid = 39795)
 x = 2
-------------------------------

I am the parent (ppid = 39794 pid = 39795)
 x = 2

I am the child (ppid = 39795, pid = 39796)
 x = 2
-------------------------------

I am the parent (ppid = 39785 pid = 39794)
 x = 3

I am the child (ppid = 39794, pid = 39797)
 x = 3
-------------------------------

I am the parent (ppid = 26178 pid = 39785)
 x = 3

I am the child (ppid = 39785, pid = 39798)
 x = 3
-------------------------------

I am the parent (ppid = 39785 pid = 39798)
 x = 3

I am the child (ppid = 39798, pid = 39799)
 x = 3
-------------------------------

I am the parent (ppid = 26178 pid = 39785)
 x = 4

I am the child (ppid = 39785, pid = 39800)
 x = 4
-------------------------------

我注意到的第一件事是,对于代码运行的每个实例,“子”的 PPID 是“父”的 PID,这很好。

但是当我手工绘制图表时: diagram of my output (I'm new so I can't post photos)

为了分配,它应该是一个平衡的树,这样一个级别的想法是有意义的。我希望将每个进程打印为图表中的一个节点,例如我使用 graphviz 绘制的图表,并且每个节点都应该包括它的 PID 和它的级别。

下面是 Geeks for Geeks 的一个例子,展示了我所说的级别:


       L1       // There will be 1 child process 
    /     \     // created by line 1.
  L2      L2    // There will be 2 child processes
 /  \    /  \   //  created by line 2
L3  L3  L3  L3  // There will be 4 child processes 
                // created by line 3

我想我过度编码了。我应该如何更改我的代码以循环分叉并获得树状结构?我正在尝试使用变量 x 来表示级别,但我不确定它是否有效,因为输出的结构对我来说是非常出乎意料的。

【问题讨论】:

  • 你画的好像是一棵树
  • 是的,但它缺乏像图中那样定义级别所需的那种组织。它应该看起来更像示例,但它无处不在
  • 为什么代码是双倍行距的?
  • 你的输出会因为缺少fflush 而变得混乱。当您调用 printf 然后 fork 而不刷新时,您应该期望数据被写入两次。如果您多次 fork 而不刷新输出流,您将看到重复的相同消息。尝试重定向到一个文件,看看会发生什么。 (当您重定向时,您可以期望 stdout 被块缓冲而不是行缓冲。)
  • @plants 也许我对“根本不是一棵树”的解释有点过于字面意思了:D

标签: c fork pid


【解决方案1】:

你的直觉有问题。在您的循环的每次迭代中,所有您的进程将分叉并创建一个新进程 - 而不仅仅是在上一次迭代中创建的进程。

因此,经过 4 次迭代,您会期望初始过程以四个孩子结束:

  • 一个有 3 个孩子(图中 55 个)
  • 一个有 2 个孩子(图中 63 个)
  • 一个有 1 个孩子(图表中的 67 个);和
  • 一个没有孩子的人(图中有 69 个)

这正是你最终得到的。如果您对每个孩子都遵循相同的逻辑并适当减少剩余循环迭代的数量,您将准确地重现您拥有的图表。

This question 不是完全相同的副本,但涵盖了大部分相同的领域。

当然,您的图表是一棵树 - 它不是完全平衡的二叉树。要获得这样的结果,您必须在每次循环迭代期间执行以下操作:

  1. fork 进程两次
  2. 在每个孩子中,立即继续到下一个循环迭代(这样它们都不会再次分叉,直到下一次迭代)
  3. 在父级中,在分叉后完全退出循环,这样它就不会再次分叉

例如:

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

int main(void) {
    int level;

    for ( level = 1; level <= 3; level++ ) {
        pid_t pids[2];

        pids[0] = fork();
        if ( pids[0] == -1 ) {
            perror("fork failed");
            exit(EXIT_FAILURE);
        } else if ( pids[0] == 0 ) {
            continue;
        }

        pids[1] = fork();
        if ( pids[1] == -1 ) {
            perror("fork failed");
            exit(EXIT_FAILURE);
        } else if ( pids[1] == 0 ) {
            continue;
        }

        for ( int i = 0; i < 2; i++ ) {
            if ( waitpid(pids[i], NULL, 0) == -1 ) {
                perror("waitpid failed");
                exit(EXIT_FAILURE);
            }
        }

        break;
    }

    printf("level %d: parent %ld, child %ld\n", level, (long) getppid(), (long) getpid());

    return 0;
}

带有输出,显示你完全平衡的二叉树:

me@mac:$ ./fork | sort
level 1: parent 62427, child 73103
level 2: parent 73103, child 73105
level 2: parent 73103, child 73106
level 3: parent 73105, child 73107
level 3: parent 73105, child 73109
level 3: parent 73106, child 73108
level 3: parent 73106, child 73111
level 4: parent 73107, child 73110
level 4: parent 73107, child 73114
level 4: parent 73108, child 73112
level 4: parent 73108, child 73116
level 4: parent 73109, child 73113
level 4: parent 73109, child 73117
level 4: parent 73111, child 73115
level 4: parent 73111, child 73118

【讨论】:

  • 你能告诉我对 waitpid 的调用在底部做什么吗?
  • @plants:它只是在等待子进程终止。 waitpidwait 更有能力,但在这个特定的示例中,它与您的 wait 调用基本相同,只是它明确指定了它要等待的进程的 PID。
  • 伙计,我希望我在这里更成熟,这样我就可以公开投票给你真正令人惊叹的回答,谢谢。我可能还有更多问题,但现在只知道你帮了我很多。
  • @plants:没问题。如果它解决了您的问题并让您满意,请不要忘记将答案标记为已接受。
  • 你能解释一下分叉两次的动机吗?
猜你喜欢
  • 1970-01-01
  • 2019-03-14
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-21
  • 2021-06-23
  • 2016-09-27
相关资源
最近更新 更多