I am trying to understand the Output of this Program. But i don't get it. I read about fork and how it works and i tried to understand it, but when i mix it with the && or || Operators i don't understand why the Output is different.
Some Times i get one word, sometimes 2, 3, 4...
#include<unistd.h>
#include<stdio.h>
int main (int argc, char *argv[]) {
(fork()&&fork()) || fork();
printf("Test\n");
return 0;
}
Any Idea how it works?
Somethings that will help in better understanding this code:
1. Fork return values - When you call fork anywhere in your code, you create a new process, and the new process also runs the same code as the parent. The difference between the parent and child process are known from the return value that fork gives. For the child process, fork return value is equal to 0, and for the parent process, it is non-zero.
2. Short circuit logic evaluation - When executing boolean logic in C, the execution is run in a short circuit way.
For a statement && where and are 2 expressions that need to be evaluated to either true or false, the second expression () is checked for its trueness only if the first expression () is evaluated to true. This is because, if is itself false, then regardless of the value of the , the resulting logical expression becomes false, hence making the evaluation of useless.
For a statement like || , is executed only if is false, for a similar reason like above.
In your code snippet, after the first fork() is executed, the child process skips the second fork (due to short circuit of &&) and goes to the third fork(). Resulting in "Test" printed 2 times.
The original parent then encounters the second fork(), and the new child process proceeds to the third fork() and prints Test 2 times again. The parent skips the third fork(), as for it, both the first and second forks are non-zero (short circuit of ||) and prints "Test" once.
Thus "Test" gets printed a total of 5 times.
P1 (fork-1)
/ \
P2(fork-2) P1 (fork-2)
/ \ / \
P3 P2 P4(fork-3) P1
/ \
P4 P5
Based on fork create successfully or not the output should be varied. If all forks are created successfully then 5 times Test should be emerged in output.
1- one output for main thread.(1)
2- main thread create two fork ( firstpart -> (fork() && fork() || secondpart->fork() ) because the first part evaluate as true and the second part do not execute in main thread. So two output should be seen here.(1+2)
3- every two created fork create a new fork but firstpart do not execute in child but secondpart are executed in each child so two another outputs would be seen in overall 5 outputs should be seen.(1+2+2)
First: Sorry for the Question. I had not done enough research, and i didn't consider each fork as child and as Parent.
What i learned is :
The first fork will run and it will create a child.Now we have 2 Processes, Parent returns a number not equal to 0 and Child return 0.
Because the Parent returned a number not 0 will the fork after && also run, and it will create another child Process. The 1 Child Process returned 0 so it wont run after &&. We now have 3 Processes
The fork after || wont run for the Parent because it returned a not 0 Number, but it will run for the child because it returned 0 so we end up with 5 Processes. Hope i am right
Related
Why does this program print “forked!” 4 times?
#include <stdio.h>
#include <unistd.h>
int main(void) {
fork() && (fork() || fork());
printf("forked!\n");
return 0;
}
The one comes from main() and the other three from every fork().
Notice that all three forks() are going to be executed. You might want to take a look at the ref:
RETURN VALUE
Upon successful completion, fork() shall return 0 to the child process and shall return the process ID of the child process to the parent process. Both processes shall continue to execute from the fork() function. Otherwise, -1 shall be returned to the parent process, no child process shall be created, and errno shall be set to indicate the error.
Note that the process id cannot be zero, as stated here.
So what really happens?
We have:
fork() && (fork() || fork());
So the first fork() will return to the parent its non zero process id, while it will return 0 to the child process. That means that the logic expression's first fork will be evaluated to true in the parent process, while in the child process it will be evaluated to false and, due to Short circuit evaluation, it will not call the remaining two fork()s.
So, now we know that are going to get at least two prints (one from main and one from the 1st fork()).
Now, the 2nd fork() in the parent process is going to be executed, it does and it returns a non-zero value to the parent process and a zero one in the child process.
So now, the parent will not continue execution to the last fork() (due to short circuiting), while the child process will execute the last fork, since the first operand of || is 0.
So that means that we will get two more prints.
As a result, we get four prints in total.
Short circuiting
Here, short circuiting basically means that if the first operand of && is zero, then the other operand(s) is/are not evaluated. On the same logic, if an operand of a || is 1, then the rest of the operands do not need evaluation. This happens because the rest of the operands cannot change the result of the logic expression, so they do not need to be executed, thus we save time.
See example below.
Process
Remember that a parent process creates offspring processes which in turn create other processes and so on. This leads to a hierarchy of processes (or a tree one could say).
Having this in mind, it's worth taking a look at this similar problem, as well as this answer.
Descriptive image
I made also this figure which can help, I guess. I assumed that the pid's fork() returned are 3, 4 and 5 for every call.
Notice that some fork()s have a red X above them, which means that they are not executed because of the short-circuiting evaluation of the logic expression.
The fork()s at the top are not going to be executed, because the first operand of the operator && is 0, thus the whole expression will result in 0, so no essence in executing the rest of the operand(s) of &&.
The fork() at the bottom will not be executed, since it's the second operand of a ||, where its first operand is a non-zero number, thus the result of the expression is already evaluated to true, no matter what the second operand is.
And in the next picture you can see the hierarchy of the processes:
based on the previous figure.
Example of Short Circuiting
#include <stdio.h>
int main(void) {
if(printf("A printf() results in logic true\n"))
;//empty body
if(0 && printf("Short circuiting will not let me execute\n"))
;
else if(0 || printf("I have to be executed\n"))
;
else if(1 || printf("No need for me to get executed\n"))
;
else
printf("The answer wasn't nonsense after all!\n");
return 0;
}
Output:
A printf() results in logic true
I have to be executed
The first fork() returns a non-zero value in the calling process (call it p0) and 0 in the child (call it p1).
In p1 the shortcircuit for && is taken and the process calls printf and terminates. In p0 the process must evaluate the remainder of the expression. Then it calls fork() again, thus creating a new child process (p2).
In p0 fork() returns a non-zero value, and the shortcircuit for || is taken, so the process calls printf and terminates.
In p2, fork() returns 0 so the remainder of the || must be evaluated, which is the last fork(); that leads to the creation of a child for p2 (call it p3).
P2 then executes printf and terminates.
P3 then executes printf and terminates.
4 printfs are then executed.
For all the downvoters, this is from a merged but different question. Blame SO. Thank you.
You can decompose the problem to three lines, the first and last lines both simply double the number of processes.
fork() && fork() || fork();
The operators are short-circuiting, so this is what you get:
fork()
/ \
0/ \>0
|| fork() && fork()
/\ / \
/ \ 0/ \>0
* * || fork() *
/ \
* *
So this is altogether 4 * 5 = 20 processes each printing one line.
Note: If for some reason fork() fails (for example, you have some limit on the number of processes), it returns -1 and then you can get different results.
Executing fork() && (fork() || fork()), what happens
Each fork gives 2 processes with respectively values pid (parent) and 0 (child)
First fork :
parent return value is pid not null => executes the && (fork() || fork())
second fork parent value is pid not null stops executing the || part => print forked
second fork child value = 0 => executes the || fork()
third fork parent prints forked
third fork child prints forked
child return value is 0 stop executing the && part => prints forked
Total : 4 forked
I like all the answers that have already been submitted. Perhaps if you added a few more variables to your printf statement, it would be easier for you to see what is happening.
#include<stdio.h>
#include<unistd.h>
int main(){
long child = fork() && (fork() || fork());
printf("forked! PID=%ld Child=%ld\n", getpid(), child);
return 0;
}
On my machine it produced this output:
forked! PID=3694 Child = 0
forked! PID=3696 Child = 0
forked! PID=3693 Child = 1
forked! PID=3695 Child = 1
This code:
fork();
fork() && fork() || fork();
fork();
gets 20 processes for itself and 20 times Printf will go.
And for
fork() && fork() || fork();
printf will go a total of 5 times.
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.
I just need to understand this statement:
if (fork() && !fork())
shouldn't it always be false? I mean, if I write:
if (a && !a)
It's always false so the first should always be false too, am I wrong? Of course I am, but I'm hoping someone can explain this strange thing to me.
I'm studying C for an exam and I had to resolve this code:
int main(){
if(fork && !fork()){
printf("a\n");
}
else printf("b\n");
}
Every calls to the unix process creation system call fork() returns twice. First it returns with the PID of the child to the parent(the process which called fork()). Second it returns to 0 to the newly created child.
from man pages:
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.
in your case
if (fork() && !fork())
The statement inside if , calls fork twice. So what will happen is following :
A
|----------------B
| |
|---C |
| | |
Now first call to fork() will return in both A and B. In A it will be nonzero and in B it will be zero.
Second call to fork() will be evoked only from A. because first fork returned 0 to B, it will not Evoke a second fork(). its because && short circuits the evaluation if first operand is found non zero. Thanks to Daniel for pointing this out.
So we can make a table out of this:
PID fork()1 fork()2
------------------------------
A >0 >0
B =0 >0
C >0 =0
So from the chart, Process C's if will be evaluated to TRUE
Its important to remember, fork()1 didn't returned to C . it got the copy of Already evaluated expression from its parent.
I hope this explains your question.
First off, is a function. It may not always return the same value.
In this case specifically, fork is a function which creates another process. The original process gets a positive return value (of the child's pid) and the child process gets a return value of 0.
In your code, there end up being a total of three processes. The if statement will evaluate to true for 1 of them (process C below).
A
|__________B
| |
|__C |
| | |
| | |
shouldn't be always false?
No.
Because it's not a variable, each call tofork() creates a new child process.
Each call to fork() returns two values, one to each process. So for each decision, there's one process that takes each path.
The fork() function call returns 0 to the child process and the process ID to the parent process. Basically, what this does is forks once. If the process is the parent, it jumps to next block, the child then forks again. The parent of this process jumps to the next block, and the child in this block executes the code in the if statement.
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.)
Why does this program print “forked!” 4 times?
#include <stdio.h>
#include <unistd.h>
int main(void) {
fork() && (fork() || fork());
printf("forked!\n");
return 0;
}
The one comes from main() and the other three from every fork().
Notice that all three forks() are going to be executed. You might want to take a look at the ref:
RETURN VALUE
Upon successful completion, fork() shall return 0 to the child process and shall return the process ID of the child process to the parent process. Both processes shall continue to execute from the fork() function. Otherwise, -1 shall be returned to the parent process, no child process shall be created, and errno shall be set to indicate the error.
Note that the process id cannot be zero, as stated here.
So what really happens?
We have:
fork() && (fork() || fork());
So the first fork() will return to the parent its non zero process id, while it will return 0 to the child process. That means that the logic expression's first fork will be evaluated to true in the parent process, while in the child process it will be evaluated to false and, due to Short circuit evaluation, it will not call the remaining two fork()s.
So, now we know that are going to get at least two prints (one from main and one from the 1st fork()).
Now, the 2nd fork() in the parent process is going to be executed, it does and it returns a non-zero value to the parent process and a zero one in the child process.
So now, the parent will not continue execution to the last fork() (due to short circuiting), while the child process will execute the last fork, since the first operand of || is 0.
So that means that we will get two more prints.
As a result, we get four prints in total.
Short circuiting
Here, short circuiting basically means that if the first operand of && is zero, then the other operand(s) is/are not evaluated. On the same logic, if an operand of a || is 1, then the rest of the operands do not need evaluation. This happens because the rest of the operands cannot change the result of the logic expression, so they do not need to be executed, thus we save time.
See example below.
Process
Remember that a parent process creates offspring processes which in turn create other processes and so on. This leads to a hierarchy of processes (or a tree one could say).
Having this in mind, it's worth taking a look at this similar problem, as well as this answer.
Descriptive image
I made also this figure which can help, I guess. I assumed that the pid's fork() returned are 3, 4 and 5 for every call.
Notice that some fork()s have a red X above them, which means that they are not executed because of the short-circuiting evaluation of the logic expression.
The fork()s at the top are not going to be executed, because the first operand of the operator && is 0, thus the whole expression will result in 0, so no essence in executing the rest of the operand(s) of &&.
The fork() at the bottom will not be executed, since it's the second operand of a ||, where its first operand is a non-zero number, thus the result of the expression is already evaluated to true, no matter what the second operand is.
And in the next picture you can see the hierarchy of the processes:
based on the previous figure.
Example of Short Circuiting
#include <stdio.h>
int main(void) {
if(printf("A printf() results in logic true\n"))
;//empty body
if(0 && printf("Short circuiting will not let me execute\n"))
;
else if(0 || printf("I have to be executed\n"))
;
else if(1 || printf("No need for me to get executed\n"))
;
else
printf("The answer wasn't nonsense after all!\n");
return 0;
}
Output:
A printf() results in logic true
I have to be executed
The first fork() returns a non-zero value in the calling process (call it p0) and 0 in the child (call it p1).
In p1 the shortcircuit for && is taken and the process calls printf and terminates. In p0 the process must evaluate the remainder of the expression. Then it calls fork() again, thus creating a new child process (p2).
In p0 fork() returns a non-zero value, and the shortcircuit for || is taken, so the process calls printf and terminates.
In p2, fork() returns 0 so the remainder of the || must be evaluated, which is the last fork(); that leads to the creation of a child for p2 (call it p3).
P2 then executes printf and terminates.
P3 then executes printf and terminates.
4 printfs are then executed.
For all the downvoters, this is from a merged but different question. Blame SO. Thank you.
You can decompose the problem to three lines, the first and last lines both simply double the number of processes.
fork() && fork() || fork();
The operators are short-circuiting, so this is what you get:
fork()
/ \
0/ \>0
|| fork() && fork()
/\ / \
/ \ 0/ \>0
* * || fork() *
/ \
* *
So this is altogether 4 * 5 = 20 processes each printing one line.
Note: If for some reason fork() fails (for example, you have some limit on the number of processes), it returns -1 and then you can get different results.
Executing fork() && (fork() || fork()), what happens
Each fork gives 2 processes with respectively values pid (parent) and 0 (child)
First fork :
parent return value is pid not null => executes the && (fork() || fork())
second fork parent value is pid not null stops executing the || part => print forked
second fork child value = 0 => executes the || fork()
third fork parent prints forked
third fork child prints forked
child return value is 0 stop executing the && part => prints forked
Total : 4 forked
I like all the answers that have already been submitted. Perhaps if you added a few more variables to your printf statement, it would be easier for you to see what is happening.
#include<stdio.h>
#include<unistd.h>
int main(){
long child = fork() && (fork() || fork());
printf("forked! PID=%ld Child=%ld\n", getpid(), child);
return 0;
}
On my machine it produced this output:
forked! PID=3694 Child = 0
forked! PID=3696 Child = 0
forked! PID=3693 Child = 1
forked! PID=3695 Child = 1
This code:
fork();
fork() && fork() || fork();
fork();
gets 20 processes for itself and 20 times Printf will go.
And for
fork() && fork() || fork();
printf will go a total of 5 times.