Johnny
Johnny

Reputation: 447

fork() start of execution

I am pretty new to unix programming and came across something I do not understand. Here it is the following code snippet:

#include <stdio.h>
#include <sys/types.h>

int main()
{
     printf("%d ", fork());
     return 0;
}

The output is: 9298 0. Why does the child process call this printf ? At my course I was told that it executes everything after the fork() call. What am I getting wrong ?

Upvotes: 1

Views: 680

Answers (4)

Luis Colorado
Luis Colorado

Reputation: 12668

Well, parameters to a function must be calculated before calling the function... so the function printf() must be called after the fork() call returns, necessarily. And this happens in the same way to the parent process and to the child.

As the previous process (the parent process) is completely duplicated in the fork() call, it returns twice (one in the parent and one in the child) both execute the printf() but with different second parameter, the parent gets the child process' process id, while the child gets a zero.

In case the fork() failed, the situation would be different, only one process (the bad called parent, as there's no child) would execute the printf() call, with the value of -1 so you should get

-1

in that case.

At last, one note: the order of the two values could be different, indeed the first number to appear is the one printed by the process that first gets to the first write() system call (this is called on the atexit() handler, before terminating, as you put no newline in the printf() call and so, the output of parent and child got buffered until the process executed the exit() function and the exit handlers were called) You can check this by executing several times the program, you will see the zero first or second, depending on the scheduling of the cpu. But the two numbers will appear one after the other (it's not possible that both appear mixed in the output) This is because both are output to the same file descriptor and the kernel impedes that both write()s be executed at the same time (the inode of the file is locked during the system call disallowing the other process to output its data)

Upvotes: 0

Ahmed Masud
Ahmed Masud

Reputation: 22374

What you were told is inaccurate. What happens is that a fork is an (almost identical) copy of the process.

So it continues with the fork() returning the values in the parent and the child. And printf continuing in both processes.

Think of the running program creating a clone (there is irony in this explanation I'll get to in a bit ;)) of itself and the two doing the same thing from that point on wards. The only difference from a program's internal perspective is the return value that the OS gives to each of the copies. The parent receives the process id (pid) of the child program whereas the child program receives a 0. This is how they can distinguish themselves from each other easily.

Snippet from the fork manual page:

The snippet below shows more details about what are the differences between the "parent" and "child" process:

   fork() creates a new process by duplicating the calling process.
   The new process is referred to as the child process.  The calling
   process is referred to as the parent process.

   The child process and the parent process run in separate memory
   spaces.  At the time of fork() both memory spaces have the same
   content.  Memory writes, file mappings (mmap(2)), and unmappings
   (munmap(2)) performed by one of the processes do not affect the
   other.

   The child process is an exact duplicate of the parent process
   except for the following points:

   *  The child has its own unique process ID, and this PID does not
      match the ID of any existing process group (setpgid(2)) or
      session.

   *  The child's parent process ID is the same as the parent's
      process ID.

   *  The child does not inherit its parent's memory locks
      (mlock(2), mlockall(2)).

   *  Process resource utilizations (getrusage(2)) and CPU time
      counters (times(2)) are reset to zero in the child.

   *  The child's set of pending signals is initially empty
      (sigpending(2)).

   *  The child does not inherit semaphore adjustments from its
      parent (semop(2)).

   *  The child does not inherit process-associated record locks
      from its parent (fcntl(2)).  (On the other hand, it does
      inherit fcntl(2) open file description locks and flock(2)
      locks from its parent.)

   *  The child does not inherit timers from its parent
      (setitimer(2), alarm(2), timer_create(2)).

   *  The child does not inherit outstanding asynchronous I/O
      operations from its parent (aio_read(3), aio_write(3)), nor
      does it inherit any asynchronous I/O contexts from its parent
      (see io_setup(2)).

Clone in Linux

If you are using Linux, the fork() call is a wrapper (actually a subset) of clone() system call. For more information on that see:

https://man7.org/linux/man-pages/man2/clone.2.html

Upvotes: 2

Some programmer dude
Some programmer dude

Reputation: 409166

When the child process starts, it starts exactly where the fork call was made, which is in the middle of a printf call.

So now both the parent and the child processes will finish their own separate printf call, each outputting its own return value.

Upvotes: 5

Alan Birtles
Alan Birtles

Reputation: 36379

The result of fork is passed to printf so it is executed before printf. Your code is equivalent to:

#include <stdio.h>
#include <sys/types.h>

int main()
{
     pid_t pid = fork();
     printf("%d ", pid);
     return 0;
}

Upvotes: 4

Related Questions