Understanding fork() in for loop - c

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.

Related

Forking in a for loop clarification

I've seen lots of examples of forking in for loops on here, but not much clarification on how it does what it does. Lets use this simple example from an answer of How to use Fork() to create only 2 child processes? as an example.
for (i = 0; i < n; ++i) {
pid = fork();
if (pid) {
continue;
} else if (pid == 0) {
break;
} else {
printf("fork error\n");
exit(1);
}
}
Most of the examples I've seen follow this general format. But what I don't understand is, how does this prevent child processes from forking as well? From my understanding, every child that gets created has to go through this loop as well. But fork() is called at the very beginning of the for loop, and then the 3 comparisons happen. Could someone explain how, even though the children seem to call fork(), this for loop still ensures only the parent can create children?
The child starts at the line after fork. fork returns 0 for the child. In your example, the child would go into the pid == 0 block and break out of the for loop.
After a fork everything is exactly the same for the child and parent (including the next instruction to execute and variable values). The only difference is the return value from fork (0 for the child, and the child's pid for the parent).
When fork returns, it actually returns twice: once to the parent and once to the child. It returns 0 to the child and it returns the pid of the child to the parent.
The if block then detects which process returned. In the parent process, if (pid) evaluates to true, so it executes continue and jumps to the top of the loop.
In the child process, if (pid) evaluates to false, then if (pid == 0) evaluates to true, so it executes break to jump out of the loop. So the child doesn't do any more forking.
But what I don't understand is, how does this prevent child processes from forking as well?
fork() returns 0 in the child. In your example code, that causes the child to break out of the loop instead of performing another iteration, so the children in fact do not call fork().
After checking my Why does this program print “forked!” 4 times?. it seems straightforward to me why.
how does this prevent child processes from forking as well?
if (pid) {
continue;
}
You see when the child is created, and then executes its code and calls fork() it becomes the parent in that stage, thus pid will be 0.
Try man 2 fork. Fork(2) returns a different value for the parent and the child, the parent gets the pid and the child gets 0.

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

fork: where does the child start running?

Is the child, after the fork, start the program from the beginning or from the place of is parent?
for example, it this program, is the child start from line 1 or line 3?
int i=1
fork()
i=i*2
fork
i=i*2
fork() creates a new process by duplicating the calling process.
The new process, referred to as the child, is an exact duplicate of
the calling process, referred to as the parent, except for the
following points: […]
from fork(2)
As it is an exact duplicate, it will also have the same instruction pointer and stack. So the child will be right after the call to fork(). Now, you may ask, how do I find out whether the current program is the child or the parent? See the manpage on the return value:
On success, the PID of the child process is returned in the parent,
and 0 is returned in the child. On failure, -1 is returned in the
parent, no child process is created, and errno is set appropriately.
So if the result of fork() is equal to 0, you're in the child process, if its greater than 0 you're in the parent and if its below 0 you're in trouble.
Please note that this implies that every code which is independent of the result value of fork(), will be executed in both the child and the parent. So if you're for example creating a pool with 16 processes, you should be doing:
for (int i = 0; i < 16; i++) {
pid_t pid = fork()
if (pid == 0) {
do_some_work();
exit(0);
} else if (pid < 0) {
// fork failed
do_some_error_handling();
}
}
If you miss the exit(0), you'll spawn 2¹⁶-1 processes (been there, just with 100 instead of 16. No fun.)
The fork starts from line 3, the point where the fork occurred.
When fork returns, it returns in both the parent (returning the PID of the child) and the child (returning 0). Execution continues from there in both the parent and the child.
As such, typical use of fork is something like:
if (0 == (child = fork()))
// continue as child.
else
// Continue as parent.
The Child will be created at line 2 i.e., fork() but it will start its execution from the line 3 i.e., i = i*2. What confuses me here is your line 4. What are you trying to do there?

Where does code Execution start in a child process?

Consider the code:
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
/* main --- do the work */
int main(int argc, char **argv)
{
pid_t child;
if ((child = fork()) < 0) {
fprintf(stderr, "%s: fork of child failed: %s\n",
argv[0], strerror(errno));
exit(1);
} else if (child == 0) {
// do something in child
}
} else {
// do something in parent
}
}
My question is from where does in the code the child process starts executing, i.e. which line is executed first??
If it executes the whole code, it will also create its own child process and thing will go on happening continuously which does not happen for sure!!!
If it starts after the fork() command, how does it goes in if statement at first??
It starts the execution of the child in the return of the fork function. Not in the start of the code. The fork returns the pid of the child in the parent process, and return 0 in the child process.
When you execute a fork() the thread is duplicated into memory.
So what effectively happens is that you will have two threads that executes the snippet you posted but their fork() return values will be different.
For the child thread fork() will return 0, so the other branch of the if won't be executed, same thing happens for the father thread.
When fork() is called the operating system assigns a new address space to the new thread that is going to spawn, then starts it, they will both share the same code segment but since the return value will be different they'll execute different parts of the code (if correctly split, like in your example)
The child starts by executing the next instruction (not line) after fork. So in your case it is the assignment of the fork's return value to the child variable.
Well, if i understand your question correctly, i can say to you that your code will run as a process already.When you run a code,it is already a process , so that this process goes if statement anyway. After fork(), you will have another process(child process).
In Unix, a process can create another process, that's why that happens.
Code execution in a child process starts from the next instruction following the fork() system call.
fork() system call just creates a seperate address space for the child process therefore it is a cloned copy of the parent process and the child process has all the memory elements of it's parent's process.
Thus, after spawning a child process through fork(), both processes (the parent process and the child process) resumes the execution right from the next instruction following the fork() system call.

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