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


int main(void) {
    for (int i = 1; i < 4; i++) {
        printf("%d", i);
        int id = fork();
        if (id == 0) {
            printf("Hello\n");
            exit(0);
        } else {
            exit(0);
        }
    }
    return 0;
}

For this code, it prints 11Hello on my computer. It seems counter-intuitive to me because "1" is printed twice but it's before the fork() is called.

Progman
  • 16,827
  • 6
  • 33
  • 48
tyy
  • 51
  • 1
  • 1
    What happens if you `fflush(stdout);` after the first print? stdout is buffered, and when the fork is done the forked process gets a copy of stdout, including a copy of the "1" sitting in the buffer. Then first process exits and stdout is flushed causing its "1" to appear, then the second process prints "Hello\n" which causes it's copy of the "1" to appear along with "Hello" and a newline. – President James K. Polk Oct 22 '21 at 00:44
  • 2
    @PresidentJamesK.Polk This should be an answer rather than a comment. – Linux Geek Oct 22 '21 at 09:04

3 Answers3

1

The fork() system call forks a new process and executes the instruction that follows it in each process parallelly. After your child process prints the value of i to the stdout, it gets buffered which then prints the value of 'i' again because stdout was not flushed.

Use the fflush(stdout); so that 'i' gets printed only once per fork.

Alternately, you could also use printf("%d\n", i); where the new line character at the end does the job.

Vens8
  • 85
  • 1
  • 8
  • 2
    Be very careful in assuming that a newline "does the job". *If* stdout is line-buffered, then appending a newline to the string passed to `printf` will trigger a flush. But you should not assume stdout is line buffered. – William Pursell Nov 01 '21 at 11:20
  • Yes, I agree and I wasn't generalizing it. That statement is specific to OP's program. Thank you. – Vens8 Nov 01 '21 at 11:41
0

To begin with, the for loop is superfluous in your example.

Recall that the child copies the caller's memory(that of its parent) (code, globals, heap and stack), registers, and open files. To be performant or there may be some other reason, the printf call may not flush the buffer and put the things passed to that except for some cases such as appending new-line-terminator.

Before forking, the parent(main process) is on the way.

Let's assume we're on a single core system and the child first preempts the core.

1 is in the buffer because its parent put it into that before forking. Then, the child reaches second print statement, a caveat here is that the child can be orphaned at that time(no matter for this moment), passing "Hello\n" string including new-line character giving rise to dump the buffer/cache(whatever you call.) Since it sees \n character, it flushes the buffer including prior 1 added by its parent, that is 11Hello.

Let's assume the parent preempts the core at first,

It surrenders after calling exit statement, bringing on the child to be orphaned, causing memory leak. After that point, the boss(init possessing process id as 1) whose newly name I forget(it may be sys-something) should handle this case. However, nothing is changed as to the printing-steps. So you run into again 11Hello except if not the buffer is flushed automagically.

I don't have much working experience with them but university class(I failed at the course 4 times). However, I can advise you whenever possible use stderr while coping with these tings since it is not buffered, in lieu of stdout or there is some magical way(I forget it again, you call it at the beginning in main()) you can opt for to disable buffering for stdout as well.

To be more competent over these topics, you should glance at The Linux Programming Interface of Michael Kerrisk and the topics related to William Pursell, Jonathan Leffler, WhozCraig, John Bollinger, and Nominal Animal. I have learnt a plethora of information from them even if the information almost wholly is useless in Turkey borders.

*Magic means needing a lot of details to explain.

0

Where does the process start to execute after fork()

fork() duplicates the image of the process and it's context. It will run the next line of code pointed by the instruction pointer.


It seems counter-intuitive to me because "1" is printed twice but it's before the fork() is called.

Read printf anomaly after "fork()"

Tony Tannous
  • 14,154
  • 10
  • 50
  • 86