user12581183
user12581183

Reputation:

How to prevent fork from returning twice,

so I am working on this C code, that print a list of child PID and parent PID

the problem that my output looks like this

digraph {
           "12896" [ label="pid 12896, level 0" ];
    "12897" [ label="pid 12897, level 1" ];
    "12896" -> "12897";
    "12898" [ label="pid 12898, level 2" ];
    "12897" -> "12898";
    "12899" [ label="pid 12899, level 3" ];
    "12898" -> "12899";
    "12900" [ label="pid 12900, level 4" ];
    "12899" -> "12900";
}digraph {
           "12896" [ label="pid 12896, level 0" ];
    "12897" [ label="pid 12897, level 1" ];
    "12896" -> "12897";
    "12898" [ label="pid 12898, level 2" ];
    "12897" -> "12898";
    "12899" [ label="pid 12899, level 3" ];
    "12898" -> "12899";
digraph {
           "12896" [ label="pid 12896, level 0" ];
    "12897" [ label="pid 12897, level 1" ];
    "12896" -> "12897";
    "12898" [ label="pid 12898, level 2" ];
    "12897" -> "12898";
digraph {
           "12896" [ label="pid 12896, level 0" ];
    "12897" [ label="pid 12897, level 1" ];
    "12896" -> "12897";
digraph {

there is 4 different digraph object, I only need the first one. also I am not sure why the first line inside digraph is tabbed, if anyone knows

here is the C code of my fork


#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("./diagraph.txt", "w+"); //my output file
    fprintf(file, "digraph {\n");
    for (i=0; i<=n; i++){

        //fflush(stdout);
        int pid = fork();

        if (pid == 0 ) {

                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 +1, file);
                        fprintf(file, "    \"%d\" -> \"%d\";\n", getppid(), getpid(), file);

                }
        }
        else{ //parent process, we will wait for the children.
        pid = waitpid(-1, &status, 0);
        return 0;
        }
    }

fprintf(file, "}");
fclose(file);

}

I am not sure of the reason of this behavior, I would like to understand it and know how to fix it thank you in advance

Upvotes: 0

Views: 225

Answers (2)

David Schwartz
David Schwartz

Reputation: 182779

While a process is executing, it may need to arrange to have a number of tasks performed when that process terminates. When you call fork, the child process inherits this arrangement from the parent. If the child process terminates normally, it will execute this list of tasks.

In general, there is no way for someone writing application code to know what's on this list. It's managed by system libraries and can contain very platform-dependent things. In this case, it's flushing standard library buffers to the file.

It is extremely important that you not let both a parent process and a child process terminate normally unless you have some way to know that this duplication of possible exit tasks created in the parent will not cause a problem. Serious bugs involving significant compromises to security-sensitive information have occurred because this has been ignored.

The simplest solution is to ensure that all processes but the initial one terminate by calling _exit. If you write to any streams in the child, you need to fflush them before the fork and fclose them in any child that used them before calling _exit.

You can, and should, use fflush if a stream is going to be accessed in both the parent and the child processes. But don't think that just because you called fflush that means it's safe to let the child terminate normally. There is no way to know (without looking closely into the particular platform's standard library implementation) what that will do.

Upvotes: 0

Chris Dodd
Chris Dodd

Reputation: 126243

By default, when you write to a file with fprintf it doesn't actually write to the file (yet) -- it just writes to a buffer. When the buffer fills up, or you later call fflush or fclose, then the data in the buffer is written to the file. The buffer is part of the FILE object stored in memory of the process, so when you call fork, the buffer and it's contents are duplicated. This results in a situation where both the child and parent may write the same data into the file, resulting in duplication.

The easiest way to avoid this is to ensure you call fflush on all FILE objects you have before calling fork, so that the buffers are all empty and no data is duplicated.

Upvotes: 1

Related Questions