There are four processes involved here, let's call them a
, b
, c
, and d
(d
is the parent of b
and c
, and b
is the parent of a
):
shell
`-d
+-b
| `-a
`-c
d
is the parent process that executes the first fork(2)
call (creating process b
). As it is the parent, it will go to the else
statement of that first if
and will fork(2)
again (creating process c
), then prints at the end the string D0
(both characters are written always together in a single write(2)
call, as printf(3)
buffers the data, see below the reason)
- the first fork of
d
produces process b
, that, after doing a second fork(2)
(getting process a
) waits for it to finish, and then prints B0
.
- the second
fork()
of b
(well, b
is created after the first fork of the listing, and only does one fork, but it is the second fork in the listing), produces process a
, that prints A0
, and then exits, making process b
able to continue after the wait(2)
call and print B0
, this forces the order to be always A0
before B0
.
- the third
fork()
produces process c
, whose task is to print C
and exit(3)
. (this makes no C0
to be output, but just C
)
- as
d
doesn't wait for any of its two children, once D0
is printed, it exit(3)
s, making the shell to output the prompt ~$
and to wait for a new command. This forces the order D0
before the shell prompt.
- the
^C
is a Control-C pressed by you, thinking that the program was still running, it makes the shell to emit a second prompt in a new line.
As far as the only processes that wait for their children are the shell (forcing the prompt to be printed after D0
), and process b
waiting for process a
(forcing always A0
to be printed before B0
) any other sequence is permitted, depending on how the system schedules the processes. and that includes the prompt. Think that the messages are always printed at the end of execution of all the processes involved.
The possible orders are the permutations of A0
, B0
, D0
, C
and the shell prompt, but of these number, half have the order of A0
and B0
changed, and of this half, half have the order of the shell and D0
exchanged... so the number of possibilities should be 5!/4 == 30
possibilities. See if you can get them all!!! :)
explanation of D0A0~$ B0C
A possible scheduling that produces the output above is the following:
- the shell starts process
d
and waits for it to finish.
- process
d
forks twice, creating processes b
and c
. Prints D0
, and exits.
- process
b
forks, and creates process a
, and waits for a
to finish.
- process
a
prints A0
and exits.
- the shell awakens from
wait()
and prints the prompt ~$
.
- process
b
awakens from wait()
for a
, and prints B0
.
- process
c
prints C
and exits.
printf()
buffering.
in terminal mode (when output is to a terminal) stdout
buffers in line mode. If you have a let's say, 512 byte buffer, it begins filling it until it sees a \n
character, or the buffer fills completely, then it flushes all buffer contents to standard output with a single write(2)
call. This makes that the sequence:
printf("D");
...
printf("0");
makes both characters to accumulate in the buffer, and be printed together at the end of the process actually, when exit(3)
calls the routine the stdio
package installs with the atexit(3)
call.
The possible outputs:
all the possible combinations are shown below:
D0A0B0C~$
, D0A0B0~$ C
, D0A0CB0~$
, D0A0C~$ B0
, D0A0~$ CB0
,
D0A0~$ B0C
, D0CA0B0~$
, D0CA0~$ B0
, D0C~$ A0B0
, D0~$ CA0B0
,
D0~$ A0CB0
, D0~$ A0B0C
, A0D0B0C~$
, A0D0B0~$ C
, A0D0CB0~$
,
A0D0C~$ B0
, A0D0~$ CB0
, A0D0~$ B0C
, A0B0D0C~$
, A0B0D0~$ C
,
A0B0CD0~$
, A0CB0D0~$
, A0CD0B0~$
, A0CD0~$ B0
, CA0B0D0~$
,
CA0D0B0~$
, CA0D0~$ B0
, CD0A0B0~$
, CD0A0~$ B0
, CD0~$ A0B0
.