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;
}
Related
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.
I have a small program written in C on linux. It's purpose is to examine the behaviour of the fork() call and the resulting child processes
Upon first inspection everything seems simple enough. However
Sometimes output is written in a funny order
Sometimes the child PPID is '1' not whatever the parent PID is.
I can't find any pattern or correlation between when it works as expected and when it does not.
I think that point 2. is probably caused by the parent process dying before the child process has executed fully. If so, is there a way to stop this from happening.
However I have no idea what is causing point 1.
Code below:
#include <stdio.h>
#include <unistd.h>
int main()
{
int x = fork();
if (x == 0)
{
printf("Child:");
printf ("\nChild PID : %d", getpid());
printf ("\nChild PPID: %d", getppid());
printf("\nHello Child World\n");
}
if (x != 0)
{
printf("Parent :");
printf ("\nParent PID : %d", getpid());
printf ("\nParent PPID: %d", getppid());
printf("\nHello Parent World\n");
}
return 0;
}
this behaviour is seen because of scheduling policy of operating system. if you are aware of process management concepts of os, then if your parent code is running and fork() is encountered, child is created, but if within that time, parent's time slice has not been completed, then parent continues running and if within its time slice, parent executes and terminates, then child becomes orphan precess and after parent process' time slice completes, child's execution starts, thats why getppid() function returns 1, because child is an orphan process and it it now adopted by init process which starts first when operating system boots and is having process id 1.
Explanation of Behaviour 1:
The order of output cannot be controlled by the program normally. That's the point of parallel process. The OS decides which process to execute at any point of time and both processes are executed simultaneously (to the human eye).
Thus the output would generally be inter-tweened.
Explanation of Behaviour 2:
You guessed that right.
The parent process has finished before the forked one.
If you want the parent pid, you can use waitpid(x, &status, 0) in the parent process if you need the parent to stay alive till child execution. This link may help you.
According to the textbook I am reading, the code below creates N child processes that will exit with unique statuses.
/* Parent creates N children */
for (i = 0; i < N; i++)
if ((pid[i] = Fork()) == 0) /* Child */
exit(100+i);
Earlier in the textbook, it states that the following code will have 8 lines of output:
int main(){
Fork();
Fork();
Fork();
printf("hello\n");
exit(0);
}
This leads me to believe that there are 2^n child processes, where n is the number of times fork() is called. Is the reason the first code only produces N child processes (as opposed to 2^N) because the child exits every time, so by the time the subsequent fork() is called, it only operates on the parent process?
Every successful call to fork(), creates a new process.
In the first example, the children processes (the return value of fork() being 0) call exit();, which means they won't call the next fork().
In the second example, every children process continues forking.
When fork() is called it copies the parent data and starts executing from that point individually. So the execution of the parent or child is depend on the scheduling of process. Whichever process get cpu time will be executed whether it is child or parent. We have to take care that which code should run by which process(child or process).
I have a problem with understanding fork(). Can anybody explain me, what will this program print? Because I preparing for the exam and it is the typical question. Exactly in this case:
#include <stdio.h>
int main(int argc, char **argv) {
int i;
for(i = fork(); i < fork(); i++)
execlp(“echo”, “sono”, argv[0], 0);
system(“echo i+$i”);
}
For me, what is not understandable is this line
for(i = fork(); i < fork(); i++)
What does it mean? Thanks to all in advance.
Crunching the first full iteration from initialization through all processes finishing the first loop context, the following will happen:
1. Initializer
i is initialized from i = fork();
Process parent: i = pid(child1)
Child process child1: i = 0
Hitting the conditional test in each process something interesting happens
2. Process : parent
i < fork() will fork another child process, child2. If the returned pid(child2) is greater than pid(child1), the conditional test is met and the parent process continues to the loop body
3. Process : child1
i is zero from the initializer
i < fork() will fork a child process, child3. If the returned pid(child3) is greater than the value of i (which is zero, so it always will be), the conditional test is met and the child1 process continues to the loop body
4. Process: child2
Inherits i from parent, where i is pid(child1)
This process was spawned from evaluating i < fork(), so fork() will eval as 0. Therefore...
i < fork() will evaluate to be child1(pid) < 0, which will never be true. The conditional test fails, and the for-loop is terminated.
5. Process: child3
Inherits i = 0 from its parent, child1.
This process was spawned from evaluating i < fork(), so fork() will eval as 0. Therefore...
i < fork() will evaluate to be 0 < 0, which will never be true. The conditional test fails and the for-loop is terminated.
At this point, parent and child1 are the only two processes that make it to the loop body. The other two (child2 and child3) both failed their conditional checks. As a result, the following things happen:
6. The Final Steps
parent process is replaced with execlp("echo", "sono", argv[0], 0);
child1 process is replaced with execlp("echo", "sono", argv[0], 0);
child2 process invokes system("echo i+$i"); and terminates.
child3 process invokes system("echo i+$i"); and terminates.
This is important: At no time do any of the aforementioned processes evaluate the for-conditional more than once. Anything that succeeds the conditional test will be replaced with an execlp() process launch. Anything that fails the conditional test will leave the loop and terminate after the system() call. Therefore, once any process makes it past the conditional (either by success or failure) it will never fork() another process.
In other words, This is NOT a fork() bomb. If either the loop body or the suffix code past the loop forked another instance of this process, it would easily be a fork() bomb, but neither do so.
Note: it is possible that a pid-rollover, where process ids reset and start "filling in the holes", causes the first initial fork to introduce a child2 pid that is less than the child1 pid. If that happens, (however unlikely) the results would only change to this:
parent process invokes system(“echo i+$i”); and terminates.
child1 process is replaced with execlp("echo", "sono", argv[0], 0);
child2 process invokes system("echo i+$i"); and terminates.
child3 process invokes system("echo i+$i"); and terminates.
Not bloody likely, but then neither is winning a lottery, and people think it will happen to them all the time.
that code is incredibly twisted and wrong.
But when you don't know what a code does, just run it "manually"
int main(int argc, char **argv) {
int i;
for(i = fork(); i < fork(); i++)
execlp(“echo”, “sono”, argv[0], 0);
system(“echo i+$i”);
}
parent process:
i = fork();
here i contains the PID of the newly created process
execlp(“echo”, “sono”, argv[0], 0);
as #Whozcraig corrected me in the comment (and shame on me for making that 1st year mistake)
it runs echo and outputs "sono a.out" on the output (considering the name of prog is a.out). execlp() replaces the current process with its arguments and stops execution here.
before edit I was saying it was fork()ing indefinitely
child process:
i = fork();
here i contains the value 0, indicating this is the newly created process.
execlp(“echo”, “sono”, argv[0], 0);
is out again… replacing current process with its arguments and stops execution once echo is over.
*before edit, I was saying it was fork()ing again.
So at first look it looks like you got a twisted and crazy fork bomb, that will grow exponentially. But in the end, you got a twisted and crazy single fork that only executes the execlp() content twice.
N.B.: system(“echo i+$i”); is nonsense, as $i has no meaning in the context of this code. Even though it will never be executed.
in the end your instructor is really perverse.
May be it look childish for most of you but I am unable to understand this small piece of code.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char** argv) {
int i, pid;
pid = fork();
printf("Forking the pid: %d\n",pid);
for(i =0; i<5; i++)
printf("%d %d\n", i,getpid());
if(pid)
wait(NULL);
return (0);
}
Out put of this program is
Forking the pid: 2223
0 2221
1 2221
2 2221
3 2221
4 2221
Forking the pid: 0
0 2223
1 2223
2 2223
3 2223
4 2223
Press [Enter] to close the terminal ...
In the for loop the printf command is used once. Why "Forking the pid" and after that the pid's are printed twice. How this is working? Can anybody explain me this? Thanks in advance.
Can anybody explain me why we have to use wait here? What I understood from the man pages is wait retuns the control to parent process? Is what I understood is correct?Is it necessary to use wait after forking a process?
Operating system : ubuntu, compiler : gcc, IDE : netbeans
But that' exactly what fork does. You forked the process and everything after the fork is done twice because now you have two processes executing the same printing code. You are basically asking why fork forks. fork forks because is is supposed to fork. That's what it's for.
After fork the parent and the child processes are generally executed in parallel, meaning that the nice sequential output you see in your example is not guaranteed. You might have easily ended up with line-interleaved output from two processes.
wait function in your case is executed from the parent process only. It makes it wait until the child process terminates, and only after that the parent process proceeds to terminate as well. Calling wait in this particular example is not really critical, since the program does nothing after that, it just terminates. But, for example, if you wanted to receive some feedback from the child process into the parent process and do some additional work on that feedback in the parent process, you'd have to use wait to wait for the child process to complete its execution.
The fork() call makes a new process. The rest of the code is then executed from each of the 2 processes. (Man page)
You're printing in both processes. Put your printing loop in an else clause of the if (pid):
pid = fork();
if(pid)
{
printf("Child pid: %d\n",pid);
wait(NULL);
}
else
{
for(i =0; i<5; i++)
printf("%d %d\n", i,getpid());
}
You see, fork returns twice, once in the parent process and once in the child process. It returns 0 in the child and the pid of the created process in the parent.
Because both the parent and child process are outputting their results.
See here: http://en.wikipedia.org/wiki/Fork_(operating_system)#Example_in_C for a good example.
fork creates a new process, and returns in both the old process (the parent) and in the new process (the child).
You can tell which one you are in by looking at the return value from fork. In the parent process it returns the PID of the child process. In the child process it return 0.