我正在尝试在C中制作fork流程调用图

问题描述

我现在在这里

#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",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和其Level。

以下是《极客》的一个例子,展示了我的意思:


       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来表示级别,但是由于输出的结构对我来说是相当意外的,因此我不确定它是否有效。

解决方法

您的直觉是错误的。在循环的每次迭代期间,您的所有 all 进程都会派生并创建一个新进程-不仅是上一次迭代中创建的进程。

因此,经过4次迭代,您希望初始过程最终有4个孩子:

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

这就是您最终得到的结果。如果您对每个子级都遵循相同的逻辑,并适当减少了剩余的循环迭代次数,则将精确地复制您拥有的图。

This question并非完全相同,但涵盖了许多相同的方面。

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

  1. 分两次进行该过程
  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