Can someone explain fork()
and give examples of its uses?
What I understood by some online sources is that:
And I have another question, for that first please take a look at my code below:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main() {
int id = fork();
int i = 45;
fork();
fork();
if(id == 0) {
printf("\nChild Process id = %d",id);
printf("\ni = %d ; i = %d",i++,i);
}
else {
printf("\nParent Process id = %d",id);
printf("\ni = %d ; i = %d",i,i+2);
}
return 0;
}
/*
O/P:
Parent Process id = 9048
i = 45 ; i = 47
Parent Process id = 9048
i = 45 ; i = 47
Parent Process id = 9048
i = 45 ; i = 47
Parent Process id = 9048
i = 45 ; i = 47
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
*/
Why doesn't the last child process display the second printf() i.e.,
printf("\ni = %d ; i = %d",i++,i);
Can you please explain why does the second printf() doesn't get executed while the first printf() gets executed for the 8th time - Child Process.
All the output you expect is there, it's just that you write it out in the background without a terminating linefeed. This means that some of the output may be obscured or overwritten by the shell prompt appearing too soon and in the middle of the program's output.
To see exactly how this is possible, here's strace
output for some of the processes in your program:
3215092 write(1, "\n", 1) = 1
3215092 write(1, "Child Process id = 0\n", 21) = 21
3215092 write(1, "i = 45 ; i = 46", 15) = 15
3215094 write(1, "\n", 1) = 1
3215094 write(1, "Child Process id = 0\n", 21) = 21
3215094 write(1, "i = 45 ; i = 46", 15) = 15
And here's how Zsh draws its prompt. First a missing linefeed indicator and then the prompt itself. Note in particular that the prompt starts with \r
, a carriage return:
3215036 write(10, "\33[1m\33[3m%\33[23m\33[1m\33[0m "..., 306) = 306
3215036 write(10, "\r\33[0m\33[23m\33[24m\33[Jmyhostname.i"..., 34) = 34
Since you fork processes in the background that write to the terminal, all your forked processes are in a race with Zsh to write their output.
Here is one possible, valid ordering that this may result in:
1. 3215036 write(10, "\33[1m\33[3m%\33[23m\33[1m\33[0m "..., 306) = 306
2. 3215092 write(1, "\n", 1) = 1
3. 3215092 write(1, "Child Process id = 0\n", 21) = 21
4. 3215092 write(1, "i = 45 ; i = 46", 15) = 15
5. 3215094 write(1, "\n", 1) = 1
6. 3215094 write(1, "Child Process id = 0\n", 21) = 21
7. 3215094 write(1, "i = 45 ; i = 46", 15) = 15
8. 3215036 write(10, "\r\33[0m\33[23m\33[24m\33[Jmyhostname.i"..., 34) = 34
Steps 1-7 happen fairly uneventfully, resulting in a screen like this (cursor marked with |
):
[...]
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46|
Since you have no terminating linefeeds, the cursor ends up after instead of under the last string.
Now, as you can see in write 8
, Zsh starts its default prompt with a leading carriage return. This means that will go to the start of the line:
[...]
i = 45 ; i = 46
Child Process id = 0
|i = 45 ; i = 46
and then proceed to overwrite the line with the prompt:
[...]
i = 45 ; i = 46
Child Process id = 0
myhostname.internal%
In effect, even though the last line of output was written to screen, the Zsh prompt effectively erased it by overwriting it using the carriage return.
You can use redirection to output to a file to more clearly see what output your program produces:
./foo > myfile
Opening the file in an editor shows your expected result:
Parent Process id = 3135806
i = 45 ; i = 47
Parent Process id = 3135806
i = 45 ; i = 47
Parent Process id = 3135806
i = 45 ; i = 47
Child Process id = 0
i = 45 ; i = 46
Parent Process id = 3135806
i = 45 ; i = 47
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46
Child Process id = 0
i = 45 ; i = 46
You can similarly add your own terminating linefeed and delay to show the output in your terminal:
./foo; sleep 5; echo
This gives the same result as above.
A correct program would output linefeeds after and not before lines, and would wait()
for each child process. (Please note that it won't work if you fix only one of these, while leaving the other)