1

I have this code:

int main(void)
{
    int f;
    for (int i = 0; i < 2; i++)
    {
        fork();
        printf("hello\n");
    }
    wait(NULL);
    printf("hello\n");
    exit(0);
}

When i run this code in the terminal, i'll get 10 lines of "hello".

But after redirecting the output to a file: ./test > file.txt I'm getting 12 lines of "hello" in the file.

Why this difference ?

Ziad
  • 11
  • 1
  • 3
    The difference is because the standard output is (by default) line buffered when connected to an interactive device, but fully buffered otherwise, such as when connected to a file. Adding an `fflush(stdiin);` after each `printf()` should help. – John Bollinger Apr 14 '23 at 23:23
  • Related: [printf anomaly after "fork()"](https://stackoverflow.com/q/2530663/24022720). – John Bollinger Apr 14 '23 at 23:26
  • 3
    Basically, the parent process writes a `"hello\n"` to `stdout`, then cycles around the loop and forks. If `stdout` is in line-buffered mode then that output is written to the terminal immediately because of the trailing newline. But if it is in fully-buffered mode then that text is still in the buffer when the parent forks, so the child gets its own copy of it along with the rest of the process state. – John Bollinger Apr 14 '23 at 23:41

1 Answers1

0

Because you just do fork but don't check the return value (for 0 to execute child code), you're forking more children than you think.

The parent also does the printf and not just the child.

And, after the first loop, the first child also does a fork so you have an unexpected grandchild.

It also acts like parent and child and both do a print.

So, you get six total prints from the loop.

And, because there is no exit call in the children, they "fall through" and execute the parent code at the bottom.

So, you get four prints from the code after the loop.

And, you should loop on wait because you fork two children but only do a single wait.


Adding some getpid and getppid calls can show what is really happening:

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

#define PRINT(_fmt) \
    printf("%d/%d " _fmt,getpid(),getppid())

int
main(void)
{
    int f;

    setlinebuf(stdout);

    for (int i = 0; i < 2; i++) {
        fork();
        PRINT("hello\n");
    }

    wait(NULL);
    PRINT("world\n");

    exit(0);
}

Here is the output:

242293/2809616 hello
242293/2809616 hello
242294/242293 hello
242294/242293 hello
242295/242293 hello
242295/242293 world
242296/242294 hello
242296/242294 world
242293/2809616 world
242294/2806078 world

Here is the corrected program:

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

#define PRINT(_fmt) \
    printf("%d/%d " _fmt,getpid(),getppid())

int
main(void)
{
    int f;

    setlinebuf(stdout);

    for (int i = 0; i < 2; i++) {
        if (fork() == 0) {
            PRINT("hello\n");
            exit(0);
        }
    }

    while (wait(NULL) >= 0);
    PRINT("world\n");

    exit(0);
}

Here is the program output:

242316/242314 hello
242315/242314 hello
242314/2809616 world
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • The question is about why the OP observes a different number of lines of output when stdout is connected to a terminal than they do when it is redirected to a file. I think you have answered a completely different question. – John Bollinger Apr 17 '23 at 18:31