Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I have different output between a terminal and a file when forking?

Tags:

c

fork

I'm learning to work with fork(), and I have some questions.

Consider the following code:

#include <stdio.h>
#include <unistd.h>

int main()
{
   int i;

   for(i = 0; i < 5; i++)
   {
      printf("%d", i);

      if((i%2)==0)
         if(fork())
            fork();
   }
}

When I output to a terminal, I get the result I expect (i.e.: 0,1,1,1,2,2,2,...). But when I output to a file, the result is completely different:

  • Case 1: (output to terminal, e.g.: ./a.out):

    Result is: 0,1,1,1,2,2,2,...

  • Case 2: (output to file, e.g.: ./a.out > output_file)

    Result is: 0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,...

Why it is like this?

like image 915
akmal Avatar asked Dec 11 '22 18:12

akmal


2 Answers

When you output to a file, the stdio library automatically block-buffers the outbound bits.

When a program calls exit(2) or returns from main(), any remaining buffered bits are flushed.

In a program like this that doesn't generate much output, all of the I/O will occur after the return from main(), when the destination is not a tty. This will often change the pattern and order of I/O operations all by itself.

In this case, the result is further complicated by the series of fork() calls. This will duplicate the partially filled and as-yet-unflushed I/O buffers in each child image.

Before a program calls fork(), one might first flush I/O using fflush(3). If this flush is not done, then you may want all processes except one (typically: the children) to _exit(2) instead of exit(3) or return from main(), to prevent the same bits from being output more than once. (_exit(2) just does the exit system call.)

like image 180
DigitalRoss Avatar answered Jan 07 '23 22:01

DigitalRoss


The fork() inside if block in your program is executed twice, because once fork is successful, the program is controlled by two processes(child and parent processes).So fork() inside if block, is executed by both child and parent processes. So it will have different output than expected since it is controlled by two different process and their order of execution is not known. ie. either child or parent may execute first after each fork()

For the difference in behaviour between the output and the file. this is the reason.

The contents you write to the buffer(to be written to file(disk) eventually) is not guaranteed to be written to the file (disk) immediatley. It is mostly flushed to the disk only after the execution of main() is complete. Whereas, it is output to terminal, during the execution of main().

Before writing to file in disk, the kernel actually copies the data into a buffer and later in the background, the kernel gathers up all of the dirty buffers, sorts them optimally and writes them out to file(disk).This is called writeback. It also allows the kernel to defer writes to more idle periods and batch many writes together.

To avoid such behaviour, it is always good to have three different condition checks in program using fork()

int pid;
if((pid = fork()) == -1 )
{ //fork unsuccessful 
 }
else if ( pid > 0)
{ //This is parent
 }
else
{//This is child
 }
like image 33
sr01853 Avatar answered Jan 08 '23 00:01

sr01853