Search code examples
cfork

using fork() to display processes tree


I need to create a process tree and display the parent and child in a graph similar to this:

this

However my result looks more like the image below:

I am not sure of what I am doing wrong, here is my code

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

int main(void){

    int i, status;
    printf( "Enter a value for n :");
    int n;
    scanf("%d", &n);

    FILE *file;
    file = fopen("./digraph.txt", "w+"); //my output file
    fprintf(file, "digraph {\n");
    for (i=0; i<n; i++){

        fflush(file);
        int pid = fork();

        if (pid == 0) {//child

            if(i == 0) { //first level
                fprintf(file, "    \"%d\" [ label=\"pid %d, level %d\" ];\n", getppid(), getppid(), i, file);
                fprintf(file, "    \"%d\" [ label=\"pid %d, level %d\" ];\n", getpid(), getpid(), i +1, file);
                fprintf(file, "    \"%d\" -> \"%d\";\n", getppid(), getpid(), file);
            }else{
                fprintf(file, "    \"%d\" [ label=\"pid %d, level %d\" ];\n", getpid(), getpid(), i , file);
                fprintf(file, "    \"%d\" -> \"%d\";\n", getppid(), getpid(), file);
            }
        }
        else {
            pid = waitpid(-1, &status, 0);
            break;
        }
    }
    if (i>n){
        fprintf(file, "}");
        fclose(file);
    }
}

Solution

  • As I was saying ... You only fork() once per iteration from within your newly created child process. So you can't really expect a tree-like view, right?

    In order to make that happen you probably need something like this going on in your loop:

    for (i=0; i<n; i++){
        fflush(file);
        pid_l = fork();
    
        if (pid_l == 0) { //left child
            if(i == 0) { //first level
                fprintf(file, "    \"%d\" [ label=\"pid %d, level %d\" ];\n", getppid(), getppid(), i);
                fprintf(file, "    \"%d\" [ label=\"pid %d, level %d\" ];\n", getpid(), getpid(), i + 1);
                fprintf(file, "    \"%d\" -> \"%d\";\n", getppid(), getpid());
            }else{
                fprintf(file, "    \"%d\" [ label=\"pid %d, level %d\" ];\n", getpid(), getpid(), i + 1);
                fprintf(file, "    \"%d\" -> \"%d\";\n", getppid(), getpid());
            }
            return 0;
        }
        else {
            printf("parent: %d left child: %d\n", getpid(), pid_l);
            pid_r = waitpid(-1, &status, 0);
        }
    
        pid_r = fork();
    
        if (pid_r == 0) { //right child
            if(i == 0) { //first level
                fprintf(file, "    \"%d\" [ label=\"pid %d, level %d\" ];\n", getppid(), getppid(), i);
                fprintf(file, "    \"%d\" [ label=\"pid %d, level %d\" ];\n", getpid(), getpid(), i + 1);
                fprintf(file, "    \"%d\" -> \"%d\";\n", getppid(), getpid());
            }else{
                fprintf(file, "    \"%d\" [ label=\"pid %d, level %d\" ];\n", getpid(), getpid(), i + 1);
                fprintf(file, "    \"%d\" -> \"%d\";\n", getppid(), getpid());
            }
        }
        else {
            printf("parent: %d right child: %d\n", getpid(), pid_r);
            pid_r = waitpid(-1, &status, 0);
            break;
        }
    }
    
    if (i == n) {
        fprintf(file, "}");
        fclose(file);
    }
    

    So the approach here - you need to fork twice, return immediately from the left child, continue on the right as the new parent.

    A few more notes on the changes:

    • you have an extra argument in all your fprintf() calls. Just drop that last file argument. There are a lot of warnings on that topic.
    • You're not properly filling in the last bracket in your dot file - replace (i > n) with i == n

    By using the reworked loop, the output looks something like this:

    enter image description here

    Which seems more like what you wanted.