I'm learning about forking processes and memory management and I have come across this piece of code:
#include <stdio.h>
#include <libc.h>
int main() {
for (int i = 0; i < 3; ++i) {
printf("*");
fflush(stdout);
fork();
}
return 0;
}
By my calculations it should produce 7 stars: initial process prints a star (1 star), forks, now we have 2 processes, each of them prints a star (1 + 2 = 3), then they fork, so we have 4 processes, each of them prints a star and then dies as the program ends.
Thus, we should get 1 + 2 + 4 = 7 stars.
However, during some runs I get only 6 stars, like in the screenshot below:
Other times when I run the program everything is good and I get 7 stars as expected.
So far I have searched in the Internet and haven't found anything like that. Debugging also didn't help.
So, what can cause this strange behavior and how can I fix it?
When running this code from a terminal you will notice that your missing * on some runs is not missing at all but printed after your program is finished.
For better understanding you might print the PID's instead of stars and an additional line when the process is about to finish:
int main() {
for (int i = 0; i < 3; ++i) {
printf("pid %d\n", getpid());
fflush(stdout);
fork();
}
printf ("pid %d terminates\n", getpid());
return 0;
}
The output on a run with missing print(s) will look something like this, indicating the terminal already returned before all processes have finished:
pid 31241
pid 31241
pid 31241
pid 31242
pid 31241 terminates
pid 31243
pid 31244 terminates
pid 31242
pid 31245
pid 31242 terminates
pid 31246 terminates
pid 31247 terminates
pid 31245 terminates
user#machine:~/bla$ pid 31243 terminates
pid 31248 terminates
To fix this you can let the parent process wait for its child processes before returning - this will cause your initial process to finish last and prevent the terminal from returning when there are still child processes running in the background:
while (wait(NULL) > 0);
printf ("pid %d terminates\n", getpid());
However, during some runs I get only 6 stars, ...
Other times when I run the program everything is good and I get 7 stars as expected.
You don't have control in which order the instances print the stars. One example of write() (called implicitly by fflush()), fork() and the implicit exit() at the end of the program could be:
instance 1: write() -> First star
instance 1: fork() -> New instance #2
instance 1: write() -> Second star
instance 2: write -> Third star
instance 2: fork() -> New instance #3
instance 1: fork() -> New instance #4
instance 1: write() -> Fourth star
instance 2: write() -> Fifth star
instance 2: exit()
instance 1: exit() -> Process #1 has finished
---- Process #1 does no longer exist ---
instance 3: write() -> Sixth star
instance 3: exit()
instance 4: write() -> Seventh star
instance 4: exit()
In the example, the sixth and the seventh star are printed, but AFTER the first process has finished.
However, the output of the program(s) is written to some "pipe" or "virtual terminal" and your text editor or IDE copies that output to the screen.
As soon as the "initial" process (instance #1) has finished, your IDE thinks that your program has finished and stops copying the data to the screen - so the sixth and the seventh star in the example are written by your program but they are not copied to the screen by the IDE.
each of them prints a star and then dies as the program ends.
... first, all 4 instances fork and then the 8 instances end.
Related
The output of the program are not obviously contents from the printf()s in teh code. Instead it looks like characters in irregular sequence. I know the reason is because the parent process and child process are running
at the same time, but in this program I only see pid=fork(), which I think means pid is only the id of child process.
So why can the parent process print?
How do the two processes run together?
// fork.c: create a new process
#include "kernel/types.h"
#include "user/user.h"
int
main()
{
int pid;
pid = fork();
printf("fork() returned %d\n", pid);
if(pid == 0){
printf("child\n");
} else {
printf("parent\n");
}
exit(0);
}
output:
ffoorrkk(()) rreettuurrnende d 0
1c9h
ilpda
rent
I focus my answer on showing how the observed output can result from the shown program. I think that it will already clear things up for you.
This is your output.
I edited it to use a good guess of what is parent (p) and child (c):
ffoorrkk(()) rreettuurrnende d 0\n
cpcpcpcpcpcpcpcpcpcpcpcpccpcpcppccc
1 c9h\n
pccpcpp
ilpda\n
ccpcpcc
rent
pppp
If you only use the chars with a "c" beneath, you get
fork() returned 0
child
If you only use the chars with a "p" beneath, you get
fork() returned 19
parent
Split that way, it should match what you know about how fork() works.
Comments already provided the actual answer to the three "?"-adorned questions in title and body of your question post.
Lundin:
It creates two processes and they are executed just as any other process, decided by the OS scheduler.
Yourself:
each time fork() is called it will return twice, the parent process will return the id of child process, and child process will return 0
Maybe for putting a more obvious point on it:
The parent process receives the child ID and also continues executing the program after the fork().
That is why the output occurs twice, similarily, interleaved, with differences in PID value and the selected if branch.
Relevant is also that in the given situation there is no line buffering. Otherwise there would be no character-by-character interleaving and everthing would be much more readable.
I get confused with this example for Fork()
int main(){
if (fork()){
if (!fork())
fork();
}
fork();
printif("1 ");
}
I count them and it'll be 12 repeated ones (how many processes will be !!!)
Let count them:
int main(){
if (fork()){ // 1
if (!fork()) // 2
fork(); // 3
}
fork(); // 4
printif("1 ");
}
When you run the program, you have the first process which will be the ancestor of all others.
fork_1 will create a child process, the latter will have 0 as returned value. so it will continue after the if statement, then runs fork_4, hence another child is created.
printf is run twice (2) for now.
Let continue with the first process that get a non-null value, it runs fork_2 and then gets a non-null returned value. It continues after the second if statement, runs fork_4. There will be two processes (the ancestor and its child process) => another two printf.
The child process created in fork_2 will get a null returned value, so the if condition is true. It runs fork_3 which gives two processes and each one of them runs fork_4. So printf will be run four (4) times.
At the end, printf is run 8 times. So you will get eight 1 printed.
I don't really understand how fork() works.I understand examples with one fork,but when there are more than one call I don't.I have an example like this and it prints 4 lines of hello, how many processes are created?
int main(void)
{
fork();
fork();
printf("hello\n");
return 0;
}
After fork() call, both processes (original and spawned) continue to execute from next line of code. So both processes execute second fork() instruction, so in the end you have 4 processes. Hence you see 4 instances of "hello" lines printed.
One picture is worth a thousand words:
The fork() syscall essentially creates a "clone" of the process executing it. Both "clones" run almost identically (except for the return value of fork()).
The first call to fork() is executed by one process (let's call that one "P"), which creates a second process "C". Now there are two processes, which both execute the second line in your main() function. So both processes, P and C, create a new process. This is why you end up with a total of 4 processes, all of which print "hello" exactly once.
The following example might make that behaviour a bit clearer:
int main() {
printf("process %d: start\n", getpid());
int r1 = fork();
printf("process %d: first fork() returned %d\n", getpid(), r1);
int r2 = fork();
printf("process %d: second fork() returned %d\n", getpid(), r2);
}
On my system, it outputs the following:
process 12953: start
process 12953: first fork() returned 12954
process 12954: first fork() returned 0
process 12953: second fork() returned 12955
process 12955: second fork() returned 0
process 12954: second fork() returned 12956
process 12956: second fork() returned 0
So, I've been trying to understand forks, and although I understand the basics (ie. another process gets created with a copy of the original data when we use fork()), I can't really grasp actually doing things with these processes that are created.
For example: I have to write a program that will call fork() twice to create 4 processes in total. When one process is created I have to print out the pid with getpid(). After printing out four ID's, my program is supposed to print a single letter 10 times.
For example, parent 1 will print 'A', child 1 will print 'B', child 2 will print 'C' and the parent of that will print 'D'. To do this, I have to use putchar(ch); and flush the output with fflush(stdout).
This means the output will look like this:
Process created, ID: 3856
Process created, ID: 3857
Process created, ID: 3858
Process created, ID: 3859
AAAAAABBBBBBBCDCDCDCDCDCDCBBBDCDCAAAADCD
So far, I've gotten the four processes to print with this code:
int main(void) {
pid_t child1, child2;
child1 = fork();
child2 = fork();
printf("Process created. ID: %d\n", getpid());
}
But I don't know how to use wait() to have everything print out randomly, after I have printed the ids.
To get everything I need to print out to be a "random mess," what should I do? Should I call functions like this?
// in main
for(int i = 0; i < 10; ++i) {
char_parent1();
char_child1();
char_parent2();
char_child2();
}
return 0;
}
void char_parent1()
{
putchar('A');
fflush(stdout);
}
void char_child1()
{
putchar('B');
fflush(stdout);
}
// and so on for char_parent2() and char_child2()
In that case, if my professor says I have to basically print things out concurrently and randomly, then why should I be using wait()?
Each process needs to know which letter it is supposed to print. That means you have to analyze the values in child1 and child2. For example, one process has two zeros; it might print D.
Arguably, each process needs to know whether it is a parent or not. If it is not a parent, it can simply exit after printing 10 copies of its letter, each followed by a fflush(). If it is a parent, after waiting for its children to die, it should exit. This means that the original process will exit last. It could usefully output a newline after its last child has died. You might or might not print diagnostic information about dead children as you go.
Consider the below code snippet:
int main()
{
fork();
fork();
fork();
printf("Hello World\n");
}
I am getting the output:[ubuntu 12.04]
aashish#aashish-laptop:~$ ./a.out
Hello World
Hello World
Hello World
aashish#aashish-laptop:~$ Hello World <---------------------------
Hello World
Hello World
Hello World
Hello World
Why "Hello Word" is outputted after the process execution is over?
The short answer is that you are creating multiple processes, which run asynchronously with respect to each other. The long answer follows:
When you type ./a.out at the shell prompt, that creates a process running your program. Let's call that process 1.
Process 1 calls fork(). This creates a new child process, Process 2, and both 1 and 2 carry on execution after the first fork() call, proceeding to the second fork() call. Process 1 creates child Process 3, and Process 2 creates child process 4. All four processes carry on from after the second fork(), proceeding to the final fork() call. Process 1 creates Process 5; Process 2 creates Process 6; Process 3 creates Process 7; and Process 4 creates Process 8.
Note that these process numbers are arbitrary: there's no guarantee they'd be created in that order.
The asynchrony comes into play as soon as that first fork() gets executed. The system offers no guarantees about scheduling the parent with respect to the child. Theoretically the child could run to completion before the parent continues, the parent could finish before the child gets any resources. The most likely scenario lies somewhere in the middle: the original process shares resources with its progeny, so that all run concurrently.
The final piece of the puzzle results from the fact that the shell is waiting for Process 1 to complete. Only Process 1. The shell doesn't know (or care) that Process 1 has started other processes. So when Process 1 completes, the shell displays a prompt. As it happened, some of the descendants of Process 1 hadn't yet reached the printf() statement. By the time they got there, the shell had already displayed its prompt.
To explore this further, you might want to try changing the fork() calls to printf( "%d\n", fork() ); and/or change printf("Hello World\n") to printf("Hello from pid %d\n", getpid() )
The "Hello World" outputs that come after the second shell prompt come from the forked processes, not from the one that was launched by the shell (you).
Thats because you make 1 fork (2), then you fork again (4), then again (8) then for each fork print Hello world. That's why you got 8 outputs.
int main() {
pid_t c[3];
int i, n = 0;
for (i = 0; i < 3; ++i) {
switch ((c[n] = fork())) {
case 0: break;
case -1: perror("fork"); exit(EXIT_FAILURE);
default: ++n;
}
}
printf("[%d] Hello World\n", (int)getpid());
// Without waiting, some children may still be running when the
// parent exits. This makes it look like output is generated
// after the process is over, when in fact not all the processes
// are done yet.
//
// The process is not really finished until its children are
// finished. The wait call waits on a child process to finish.
for (i = 0; i < n; ++i) wait(0);
return 0;
}