I don't understand this diagram of fork() - c

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.)

Related

nested fork () - how to count number of processes

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.

If you have a break inside an if statement that creates a child process in a for loop, does the loop no longer execute?

I am going through a code example in my textbook (dining philosophers problem) and in the main method, right before the return 0; statement, there is the block of code I've included below. This loop is supposed to create the philosophers each as a concurrent forked process. This means that each philosopher executes philosopher(i).
However, since right after the if statement, there follows a break, doesn't that mean only the first philosopher (i = 0) is created?
for (i = 0; i < N - 1; ++i)
if (fork() == 0)
break;
philosopher(i) ;
fork(2) "splits" the process calling it into two independent processes, the second a child of the first. In the parent process (the original process), it returns the PID of the child. In the child process, fork() returns 0.
So in your example, the loop only breaks in the child process, while continuing in the parent process to spawn the remaining philosophers.
The loop executes N - 1 times, spawning N - 1 child philosophers. After completing the loop, the parent process also calls philosopher(i), running the Nth and final philosopher.
fork() returns twice: in the parent with a non-zero value (a positive pid on success or a negative value on failure) and in the child with pid==0 (if the call succeeded).
if (fork() == 0) will break the loop in the child, so that the child continues at philosopher(i); (where the parent will also continue but only after all the loop iterations are over).
In other words,
for (i = 0; i < N - 1; ++i)
if (fork() == 0)
break;
philosopher(i) ;
tries to (fork() not checked against failure) run philosopher(i); in i=0 to i==N-2 incl. child processes and then runs it with i==N-1 in the parent.

Visually what happens to fork() in a For Loop

I have been trying to understand fork() behavior. This time in a for-loop. Observe the following code:
#include <stdio.h>
void main()
{
int i;
for (i=0;i<3;i++)
{
fork();
// This printf statement is for debugging purposes
// getppid(): gets the parent process-id
// getpid(): get child process-id
printf("[%d] [%d] i=%d\n", getppid(), getpid(), i);
}
printf("[%d] [%d] hi\n", getppid(), getpid());
}
Here is the output:
[6909][6936] i=0
[6909][6936] i=1
[6936][6938] i=1
[6909][6936] i=2
[6909][6936] hi
[6936][6938] i=2
[6936][6938] hi
[6938][6940] i=2
[6938][6940] hi
[1][6937] i=0
[1][6939] i=2
[1][6939] hi
[1][6937] i=1
[6937][6941] i=1
[1][6937] i=2
[1][6937] hi
[6937][6941] i=2
[6937][6941] hi
[6937][6942] i=2
[6937][6942] hi
[1][6943] i=2
[1][6943] hi
I am a very visual person, and so the only way for me to truly understand things is by diagramming. My instructor said there would be 8 hi statements. I wrote and ran the code, and indeed there were 8 hi statements. But I really didn’t understand it. So I drew the following diagram:
Diagram updated to reflect comments :)
Observations:
Parent process (main) must iterate the loop 3 times. Then printf is called
On each iteration of parent for-loop a fork() is called
After each fork() call, i is incremented, and so every child starts a for-loop from i before it is incremented
At the end of each for-loop, "hi" is printed
Here are my questions:
Is my diagram correct?
Why are there two instances of i=0 in the output?
What value of i is carried over to each child after the fork()? If the same value of i is carried over, then when does the "forking" stop?
Is it always the case that 2^n - 1 would be a way to count the number of children that are forked? So, here n=3, which means 2^3 - 1 = 8 - 1 = 7 children, which is correct?
Here's how to understand it, starting at the for loop.
Loop starts in parent, i == 0
Parent fork()s, creating child 1.
You now have two processes. Both print i=0.
Loop restarts in both processes, now i == 1.
Parent and child 1 fork(), creating children 2 and 3.
You now have four processes. All four print i=1.
Loop restarts in all four processes, now i == 2.
Parent and children 1 through 3 all fork(), creating children 4 through 7.
You now have eight processes. All eight print i=2.
Loop restarts in all eight processes, now i == 3.
Loop terminates in all eight processes, as i < 3 is no longer true.
All eight processes print hi.
All eight processes terminate.
So you get 0 printed two times, 1 printed four times, 2 printed 8 times, and hi printed 8 times.
Yes, it's correct. (see below)
No, i++ is executed after the call of fork, because that's the way the for loop works.
If all goes successfully, yes. However, remember that fork may fail.
A little explanation on the second one:
for (i = 0;i < 3; i++)
{
fork();
}
is similar to:
i = 0;
while (i < 3)
{
fork();
i++;
}
So i in the forked processes(both parent and child) is the value before increment. However, the increment is executed immediately after fork(), so in my opinion, the diagram could be treat as correct.
To answer your questions one by one:
Is my diagram correct?
Yes, essentially. It's a very nice diagram, too.
That is to say, it's correct if you interpret the i=0 etc. labels as referring to full loop iterations. What the diagram doesn't show, however, is that, after each fork(), the part of the current loop iteration after the fork() call is also executed by the forked child process.
Why are there two instances of i=0 in the output?
Because you have the printf() after the fork(), so it's executed by both the parent process and the just forked child process. If you move the printf() before the fork(), it will only be executed by the parent (since the child process doesn't exist yet).
What value of i is carried over to each child after the fork()? If the same value of i is carried over, then when does the "forking" stop?
The value of i is not changed by fork(), so the child process sees the same value as its parent.
The thing to remember about fork() is that it's called once, but it returns twice — once in the parent process, and once in the newly cloned child process.
For a simpler example, consider the following code:
printf("This will be printed once.\n");
fork();
printf("This will be printed twice.\n");
fork();
printf("This will be printed four times.\n");
fork();
printf("This will be printed eight times.\n");
The child process created by fork() is an (almost) exact clone of its parent, and so, from its own viewpoint, it "remembers" being its parent, inheriting all of the parent process's state (including all variable values, the call stack and the instruction being executed). The only immediate difference (other than system metadata such as the process ID returned by getpid()) is the return value of fork(), which will be zero in the child process but non-zero (actually, the ID of the child process) in the parent.
Is it always the case that 2^n - 1 would be a way to count the number of children that are forked? So, here n=3, which means 2^3 - 1 = 8 - 1 = 7 children, which is correct?
Every process that executes a fork() turns into two processes (except under unusual error conditions, where fork() might fail). If the parent and child keep executing the same code (i.e. they don't check the return value of fork(), or their own process ID, and branch to different code paths based on it), then each subsequent fork will double the number of processes. So, yes, after three forks, you will end up with 2³ = 8 processes in total.

C: fork() child processes

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).

Understanding fork() in for loop

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.

Resources