Reputation: 447
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
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
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.
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)).
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
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
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