Reputation: 11
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int pid;
int x, y;
x = 10;
y = 10;
pid = fork();
if (pid != 0)
{
x++;
y--;
}
printf("x = %i y = %i\n", x, y);
pid = fork();
if (pid != 0)
{
x++;
y--;
}
printf("x = %i y = %i\n", x, y);
return (0);
}
I am completely confused by this part of the code. Can anyone explain me how it works? Also I can't understand which process (child/parent) prints.
Upvotes: 1
Views: 6947
Reputation: 753990
The fork()
function is unusual; it returns twice, once in each of two different (but closely related) processes, unless it fails. It returns -1
if it fails (in the original process, of necessity). If it succeeds, it returns 0
in the child process, while it returns the PID of the child process in the original (parent) process, which is never 0
(or negative).
You should learn to instrument code. In the context of code using fork()
, it is usually effective to print the PID (process ID) and the PPID (parent process ID) to help disambiguate which process prints what. The short answer to your question about which process prints is that two processes print the data from the first printf()
call, and four processes print the data from the second printf()
call – unless you pipe the output of the program to another (such as cat
), in which case it appears that some processes print the data multiple times. (See also printf()
anomaly after fork()
.)
Let's instrument your code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
printf("PID = %d\n", (int)getpid());
int x = 10;
int y = 10;
int pid = fork();
if (pid != 0)
{
x++;
y--;
}
printf("1: x = %i y = %i (PID %d, PPID %d)\n",
x, y, (int)getpid(), (int)getppid());
pid = fork();
if (pid != 0)
{
x++;
y--;
}
printf("2: x = %i y = %i (PID %d, PPID %d)\n",
x, y, (int)getpid(), (int)getppid());
int status;
int corpse;
while ((corpse = wait(&status)) > 0)
{
printf("%d: child %d exited with status 0x%.4X\n",
(int)getpid(), corpse, status);
}
return (getpid() % 16);
}
The return statement at the end of main()
returns non-zero exit status 15 times out of 16 just to make things a little more interesting.
Examples runs (of program ./fork43
built from fork43.c
) — one without piping, one with piping:
$ ./fork43
PID = 26226
1: x = 11 y = 9 (PID 26226, PPID 23612)
2: x = 12 y = 8 (PID 26226, PPID 23612)
1: x = 10 y = 10 (PID 26227, PPID 26226)
2: x = 11 y = 9 (PID 26228, PPID 26226)
2: x = 11 y = 9 (PID 26227, PPID 26226)
26226: child 26228 exited with status 0x0400
2: x = 10 y = 10 (PID 26229, PPID 26227)
26227: child 26229 exited with status 0x0500
26226: child 26227 exited with status 0x0300
$ ./fork43 | cat
PID = 26230
1: x = 11 y = 9 (PID 26230, PPID 23612)
2: x = 11 y = 9 (PID 26233, PPID 26230)
PID = 26230
1: x = 10 y = 10 (PID 26232, PPID 26230)
2: x = 10 y = 10 (PID 26234, PPID 26232)
PID = 26230
1: x = 10 y = 10 (PID 26232, PPID 26230)
2: x = 11 y = 9 (PID 26232, PPID 26230)
26232: child 26234 exited with status 0x0A00
PID = 26230
1: x = 11 y = 9 (PID 26230, PPID 23612)
2: x = 12 y = 8 (PID 26230, PPID 23612)
26230: child 26233 exited with status 0x0900
26230: child 26232 exited with status 0x0800
$
In the first run, the initial (parent) process has PID 26226. It forks, and its child is 26227. The parent process is told its child PID, so it increments x
and decrements y
; it then executes the printf()
statement where the format string starts 1:
, printing the values x
as 11 and y
as 9. In this run, the parent process forks again creating its second child with PID 26228. The parent increments x
and decrements y
again, and executes the printf()
statement where the format string starts 2:
before anything else happens. It then reaches the wait()
loop and waits for one of its children to die.
Then the first child process (26227) executes the printf()
statement where the format string starts 1:
but the values of x
and y
are both unchanged at 10. It then reaches the second fork and creates its own child (the original process's grandchild) process with PID 26229.
The second child 26228 has the (x, y) values (11, 9) because those were the values when it was forked, so it prints those values when it executes the printf()
statement where the format string starts with 2:
.
After the first child forks, it gets told its child's PID, so it increments x
and decrements y
, printing the values 11 and 9.
The second child exits and its status is reported by the original process. The grandchild process now executes the printf()
statement where the format string starts with 2:1. Since the value in
pidwas 0 twice, the values in
xand
y` are still unchanged at 10. It then exits.
The first child can report that its child exited, and then itself exits. The parent process reports that the first child exited and also exits.
Overall, there is one copy of the PID
output, two copies of 1:
, and 4 copies of 2:
(plus three 'child exited' reports).
The second run, with the output piped to cat
, shows that the output is fully buffered instead of line buffered, so processes flush the written data as they exit, not when newlines are printed. This is why there are 4 copies of the introductory PID = 26230
output, and 4 copies of the 1:
output as well. There are still just 3 'child exited' reports.
Printing the PID information like this is a valuable aid towards understanding the code. It is important to recognize that the sequence of output is not fixed. Different runs could produce different sequences (quite apart from the different PID numbers) simply because of the scheduling algorithm and what else is happening on the computer at the same time.
Upvotes: 2
Reputation: 11921
Here
pid = fork();
fork()
creates a new process by duplicating the calling process & first it returns the child process pid to the parent, so this
if (pid != 0) { } /* 2345 != 0 i.e parent process, lets assume pid returned is 2345 */
gets true i.e parent process and then it returns 0
to the child process, so next it looks like
if (pid != 0) { /* 0 != 0 .. child process */ }
From the manual page of fork()
RETURN VALUE On success, the PID of the child process is returned in the parent, and 0 is returned in the child. On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately.
Also fork()
return type should be of pid_t
not of int
type. correct one is
pid_t pid = fork();
Upvotes: 0