fork() execution in for loop - c

int main(int argc, char** argv) {
int i = 0;
while (i < 2) {
fork();
system("ps -o pid,ppid,comm,stat");
i++;
}
return (EXIT_SUCCESS);
}
Can anyone tell me how many times ps command is executed with an explanation?

I believe the answer is 6.
in the first iteration, fork() is called, splitting the process in 2, thus calling ps twice.
in the second iteration, fork is called again in each process, so you now have 4 processes running ps.
total calls to ps: 2+4=6.

6 times.
It creates a process tree like this:
A-+
|-B-+
| |-C-+
|-D
A does it twice (i=0)
B does it twice (i=0)
C does it once (i=1)
D does it once (i=1)
Note that my usage of letters is to distinguish them. There's no predictable output ordering since process switching is non-deterministic to the eyes of a programmer.

Initial Process
i == 0
-> Fork 1
system call
i == 1
-> Fork 1.1
system call
system call
system call
i == 1
-> Fork 2
system call
system call
I count 6, 2 each from the initial process and the first fork (4), and one from each process forked when i == 1 from those 2 processes.
Of course that's assuming you fix the missing end brace (and define EXIT_SUCCESS), otherwise none, since it won't compile. :-)

Related

Some explanation of the behavior of the fork system call?

I'm studying for the operating system exam and now I'm seeing a code for the behavior of the fork() system call.The main goal is to draw the tree of processes made by this code.I did it but I can't explain because when I run this code,it prints 6 times glob's values two of which different while all other equal.Why does it?It should not print a single value of glob(Precisely the value 2 of the variable glob)?Thanks to everyone!
this is the code:
int main(int argc,char* argv[]){
int glob=5;
int pid=0;
pid=fork();
glob--;
pid=fork();
glob--;
if (pid!=0) {
pid=fork();
glob--; }
printf("Value=%d\n",glob);
return 0;
}
You start with process 1.
The first call to fork creates a new process - 2.
Now, 1 and 2 keep running. Both call fork again, you have now created process 3 and 4.
Now you check if the returned pid is 0. If it isn't (which it won't be in process 1 and 2), you call fork again in process 1 and 2 and create process 5 and 6.
Processes 1, 2, 3, 4, 5, and 6 now call printf.
Because you are creating a three duplicate processes, Then original and duplicate processes operations are happening at the same time, some operations take longer than others.
After first call to fork() you have two processes with variable glob decremented to 4.
After second call to fork() you have four processes with variable glob decremented to 3.
But then, only the ones that were parents in the second call (they received != 0 from the second call to fork(), these are two processes in total) do a third call to fork() (becoming four processes) and decrement the variable glob again to 2---this is, the parents and the children, a total of four processes of a total of six)
so only four processes from the total of six, do the third decrement of glob and so, you expect four 2 values and two more with 3.

Understanding POSIX - fork()

I was reading about the fork function and how it creates new processes. The following program runs fine and prints here sixteen times, but, I am having trouble understanding the flow of execution:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
int main()
{
int i;
for (i = 0; i < 4; i++) { // line no. 12
fork(); // line no. 13
}
printf("%s\n", "here");
return 0;
}
It seems to me that there are two ways this program can be viewed as:
1st approach: fork() is called a total of four times. If I replace the loop with four calls to the fork() function, things seem to fall in place and I understand why here is printed 2 ^ 4 times.
2nd approach: fork() spawns a new process exactly from where it is invoked and each of these child processes have their own local variables. So, after line no. 13, each of these child processes see the end of the loop (}) and they go to line no. 12. Since, all these child processes have their own local variable i set to 0 (maybe i is set to some garbage value?), they all fork again. Again for these child processes their local variable i is set to 0. This should result in a fork bomb.
I am certainly missing something in my 2nd approach could someone please help?
Thanks.
Your 2nd approach is not right. Because after fork() the child process inherits the current value of i. It's nneither set to 0 everytime fork() is called nor do they have garbage value. So, your code can't have a fork bomb. The fact that it's a local variable is irrelevant. fork() clones pretty much everything and the child process is identical to its parent except for certain things as noted in the POSIX manual.
I'll reduce the loop count to 2 for ease of explaining and assume all fork() calls succeed:
for (i = 0; i < 2; i++) {
fork();
}
printf("%s\n", "here");
1) When i=0, fork() is executed and there are two processes now. Call them P1 and P2.
2) Now, each P1 and P2 processes continue with i=0 the loop and increment i to 1. The for loop condition is true, so each of them spawn another two processes and in total 4. Call them P1a & P1b and P2a & P2b. All 4 processes now have i=1 and increment it to 2 (as they continue the loop).
3) Now, all 4 processes have the value of i as 2 and for loop condition is false in all of them and "here" will be printed 4 times (one by each process).
If it helps, you can convert the for loop to a while loop and how i gets incremented by both processes returning from each fork() might become a bit more clear:
i = 0;
while(i < 2) {
fork();
i++;
}
printf("%s\n", "here");
Your first approach was right.
That's a rather boring answer, so I'll give you all the technical details.
When fork is called, several things happen:
A new process is created ('the child')
The stack of the parent is duplicated, and assigned to the child.
The stack pointer of the child is set to that of the parent.
The PID (process ID) of the child is returned to the parent.
Zero is returned to the child
variables declared inside a function are stored in the stack, and are therefore start at the same value, but are not shared.
variables declared outside a function (at the top level) are not in the stack, so are shared between child/parent.
(Some other things are or are not duplicated; see man fork for more information.)
So, when you run your code:
what happens # of processes
1. the parent forks. 2
2. the parent and it's child fork. 4
3. everyone forks 8
4. everyone forks 16
5. everyone prints "here". 16
You end up with sixteen processes, and the word 'here' sixteen times.
basically,
if(fork() != 0) {
parent_stuff();
} else {
child_stuff();
}
Using following code and you can easily see how fork create the value of variable i:
for (i = 0; i < 4; i++) {
printf("%d %s\n", i, "here");
fork();
}
As what you could expect, the child process copy the value of parent process and so we get 0 line with i = 0; 2 lines with i = 1; 4 lines with i = 2 and 8 lines with i = 3. Which I think answers your 2nd question.

In a fork() program what is executed first? Parent or child?

I don't know what is executed first in fork. For example I have this code:
int main() {
int n = 1;
if(fork() == 0) {
n = n + 1;
exit(0);
}
n = n + 2;
printf(“%d: %d\n”, getpid(), n);
wait(0);
return 0;
}
What will this print on the screen?
1: 3
0: 4
or
0: 4
1: 3
It's not specificed. It's up to the OS scheduler to decide which process to schedule first.
After a fork(), it is indeterminate which process—the parent
or the child—next has access to the CPU. On a multiprocessor system,
they may both simultaneously get access to a CPU.
When I run this program, it only prints one line, instead of two, because it exit()s in the fork()'s block.
So the question is, did you forget a printf() in the fork()'s block, or shouldn't the exit() be there?
If you want to make one process run before the other,try using sleep() system call.

Fork() command issue

While going thorough fork() command i got struck with a question .
how many no.of processes are created by the end of 12th second, if
time starts from 0th second? Process id's start from 0.
Pseudo code
while(true)
{
sleep 1second;
if( getpid() % 2 == 0 )
{
fork();
printf("Hello\n");
}
}
when i run above code on my system it is not showing output on konsole. Is no . of process at end of 12 sec is dependent on OS ?Need suggestion as i am not good in fork()
Since when do process IDs "start at 0"? Not even when the system boots; the first process has the id 1 :-)
You're only fork()ing when your own process ID is even; so if it happens to be odd then nothing will happen... which means that if you run the program several times, sometimes it will do something and sometimes it won't.
Add this after your printf:
fflush(stdout);
But you have a fundamental problem with your logic. fork() returns 0 in the child, and the child pid in the parent. You don't check, so both the parent and the child continue doing the loop, which happens again, and again, and again, forever. You need to change the loop body to this:
if(fork() == 0)
{
printf("Hello!\n");
fflush(stdout);
}

I don't understand this diagram of fork()

How we can get this process with this condition??schema of process?
int main (int argc, char **argv) {
int i;
int pid;
for (i= 0; i < 3; i++) {
pid = fork();
if (pid < 0) break;// with this condition i dont understand??
}
while (wait(NULL) != -1);
fork() splits a process in two, and returns 0 (if this process is the child), or the PID of the child (if this process is the parent), or -1 if the fork failed. So, this line:
if (pid < 0) break;
Says "exit the loop if we failed to create a child process".
The diagram is a little confusing because of the way the processes (circles) correspond to the fork() calls in the loop. The three child processes of the main process are created when i is 0, 1, and 2 respectively (see the diagram at the bottom of this post).
Since the loop continues in both the parent and the child process from the point fork was called, this is how the forks happen:
i == 0: fork is called in the original parent. There are now two processes (the top one, and the left one).
i == 1: fork is called in the two existing processes. New children are the leftmost child on the second layer from the bottom, and the middle child on the third layer from the bottom. There are now four processes
i == 2: fork is called in all existing processes. New children are all remaining nodes (the bottom node, the two rightmost nodes in the second layer from the borrom, and the rightmost node in the third layer from the bottom)
i == 3: All 8 processes exit the loop
Here is the diagram again, with numbers indicating what the value of i was in the loop when the process was created:
-1 <--- this is the parent that starts the loop
/ | \
0 1 2
/ \ |
1 2 2
|
2
To understand your diagram you must rely on the behavior of fork: it splits the process in two, creating another process identical to the first (except for the PID) in a new memory location.
If you call it in a loop that's what happen:
When i=0 the first process will be split, creating another process that will start running from exactly this point on (so will skip the first loop). Focusing on the first process, it will continue the loop, generating another process when i=1. The second process, thus, will start from i=1, so will skip the first two loops. The first process will be split last time for i=2. The last copy created, however, will start running from i=2, so it will exit the loop and will not generate anything.
The first copy created will start the loop from i=1, generating two process, while the second copy will start from i=2, generating only one copy.
You can continue this reasoning and understand the rest of the diagram.
As others pointed out, if (pid < 0) is just a check to see if there are errors and does not modify the logic of the code.
fork returns -1 if the fork call failed. it returns the pid in parent and 0 in the child. The condition you're looking at doesn't really matter to the functioning of the code; it's just saying if there's an error with fork then exit the loop. If there's no error in the fork call then the process tree in your diagram will be built.
The reason why is that the same loop will continue running in the child processes. So the children will also continue to fork based on the value of i at the time fork was called.
fork return -1 on error, and 0 or positive else, so the line if (pid < 0) break; says "if there was error, exit from the loop".
Assuming that there is not error, it's something like:
At the beginning, i=0, and you have one process. let's call it p0.
In the line fork();, p0 creates another process. let's call it p1.
In everyone of them, we have i++ (so now i is 1), and we are iterating the loop again.
p0 and p1, separately, have a fork(); command, so everyone of them creates another process. let's call the new processes p2 and p3.
Now, in every process, we have i++, that set i to be 2, and we run the loop again.
Everyone of the 4 processes we have, run the line fork();, and creates a new process. so now we have also p4,p5,p6,p7.
Every process increase its i to 3, and then, since the loop condition is now false, the loop finally ends.
Now, the 8 process arrive (separately) to the next line.
(In fact, every iteration double the number of processes, so if you change the 3 to, for example, 15, you will have 2^15 processes at the end.)

Resources