#include <stdio.h>
#include <unistd.h>
int main()
{
fork();
fork() && fork() || fork();
fork();
printf("forked\n");
return 0;
}
It cause difficulty to understand how to calculate number of processes spawned after executing the program?
Help me to find out.
Platform --UBUNTU 10.04
Let's follow the fork-tree, assuming none of the forks fails
fork();
Now we have two processes, so far it doesn't matter who's child and who parent, call them p1 and p2
fork()
Both of those processes spawn another child, so we have 4 processes, for two of them (p3, p4) the result is zero, for the other two (p1 and p2) it's nonzero
&& fork()
p1 and p2 fork again, giving p5 and p6, six processes total. In p1 and p2, the && evaluates to true, so they don't fork again in this line. For p3, p4, p5, p6, the && evaluates to false, so they fork
|| fork();
here, spawning four new processes, giving a total of 6 + 4 = 10.
fork();
each of the 10 processes forks again, makes 20.
You should not use fork() like this. Never. And, nevertheless, you won't need to do so in real life.
How to use it:
int main() {
/* code */
pid_t pid = fork();
if (pid < 0) {
/* error, no child process spawned */
}
if (pid > 0) {
/* we are the parent process, pid is the process ID of the ONE child process spawned */
}
/* else, we are the child process, running exactly one command later the fork() was called in the parent. */
/* some more code */
return 0;
}
fork();
fork system call returns an integer: the PID of the process in the parent process and 0 in the child process. If an error occurs, no process is created and -1 is returned.
|| and && are logical operators.
If the result of the operator is know after the evaluation of their left operand, they are required to short-circuit (i.e., not evaluate the right operand):
for || operator its right operand is not evaluated if its left operand is != 0
for && operator its right operand is not evaluated if its leftt operand is == 0
Save the file, say as fork-count.c. Then compile it with gcc fork-count.c -o fork-count. Then you can run it and count the number of lines of output with ./fork-count | wc -l.
I have found the correct explanation of this question on Geeks for Geeks:
A fork() system call spawn processes as leaves of growing binary tree. If we call fork() twice, it will spawn 22 = 4 processes. All these 4 processes forms the leaf children of binary tree. In general if we are level l, and fork() called unconditionally, we will have 2l processes at level (l+1). It is equivalent to number of maximum child nodes in a binary tree at level (l+1).
As another example, assume that we have invoked fork() call 3 times unconditionally. We can represent the spawned process using a full binary tree with 3 levels. At level 3, we will have 23 = 8 child nodes, which corresponds to number of processes running.
A note on C/C++ logical operators:
The logical operator && has more precedence than ||, and have left to right associativity. After executing left operand, the final result will be estimated and execution of right operand depends on outcome of left operand as well as type of operation.
In case of AND (&&), after evaluation of left operand, right operand will be evaluated only if left operand evaluates to non-zero. In case of OR (||), after evaluation of left operand, right operand will be evaluated only if left operand evaluates to zero.
Return value of fork():
The man pages of fork() cites the following excerpt on 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.”
A PID is like handle of process and represented as unsigned int. We can conclude, the fork() will return a non-zero in parent and zero in child. Let us analyse the program. For easy notation, label each fork() as shown below,
#include <stdio.h>
int main()
{
fork(); /* A */
( fork() /* B */ &&
fork() /* C */ ) || /* B and C are grouped according to precedence */
fork(); /* D */
fork(); /* E */
printf("forked\n");
return 0;
}
The first two fork() calls are called unconditionally.
At level 0, we have only main process. The main (m in diagram) will create child C1 and both will continue execution. The children are numbered in increasing order of their creation.
At level 1, we have m and C1 running, and ready to execute fork() – B. (Note that B, C and D named as operands of && and || operators). The initial expression B will be executed in every children and parent process running at this level.
At level 2, due to fork() – B executed by m and C1, we have m and C1 as parents and, C2 and C3 as children.
The return value of fork() – B is non-zero in parent, and zero in child. Since the first operator is &&, because of zero return value, the children C2 and C3 will not execute next expression (fork()- C). Parents processes m and C1 will continue with fork() – C. The children C2 and C3 will directly execute fork() – D, to evaluate value of logical OR operation.
At level 3, we have m, C1, C2, C3 as running processes and C4, C5 as children. The expression is now simplified to ((B && C) || D), and at this point the value of (B && C) is obvious. In parents it is non-zero and in children it is zero. Hence, the parents aware of outcome of overall B && C || D, will skip execution of fork() – D. Since, in the children (B && C) evaluated to zero, they will execute fork() – D. We should note that children C2 and C3 created at level 2, will also run fork() – D as mentioned above.
At level 4, we will have m, C1, C2, C3, C4, C5 as running processes and C6, C7, C8 and C9 as child processes. All these processes unconditionally execute fork() – E, and spawns one child.
At level 5, we will have 20 processes running. The program (on Ubuntu Maverick, GCC 4.4.5) printed “forked” 20 times. Once by root parent (main) and rest by children. Overall there will be 19 processes spawned.
Related
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
ca anyone tell me what process tree will be generated by this c code?
#include <unistd.h>
int main(void)
{
fork() || (fork() && fork());
return 0;
}
Likely this is a homework. However, it is interesting.
First of all:
fork() returns 0 for the child.
fork() returns a value unequal to 0 for the parent.
Therefore in the server the first part of the logical or (||) unequals 0 and the rest of the expression is not executed on the parent: One call to fork.
In the child the first part is 0, so the rest fork() && fork() is executed. So on this child the first fork() returns a value unequal to zero causing to evaluate the second part. Therefore there are two new children. Both of them get a return value of 0, short-circuiting the evaluation.
Not tested, typed in Safari.
When I run this code, it prints "hello world" 20 times. As per my understanding it should be print it 32 times. Also, the newline gets printed differently with each run. I don't understand this. Please help.
int
main(int argc, char** argv){
if(fork() || fork())
fork();
if(fork() && fork())
fork();
printf("\nhello world");
return 0;
}
To understand you will have to disect both constructs. First the construct
if( fork() || fork() )
fork();
or written in another way by unfolding the short-circuit or:
if( !fork() )
if( !fork() )
goto not_taken;
fork();
not_taken:
or without goto's
if( !fork() ) {
if( fork() )
fork();
}
else
fork();
will five-fold the number of processes. This is because first the original process forks, then in the child as the fork will return zero it will fork again (short-circuit or). Then if any of these returned non-zero (that is the parent of the fork) it will fork again - this happens to be done in the parent process and it's child. That is the forks in the conditions will be called once and the last fork will be run once.
Now for the second construct:
if( fork() && fork() )
fork();
or with unfolding short-circuit and:
if( fork() )
if( fork() )
fork();
the process count will four-fold. The reason is that first fork will be run in the parent process and if that returns non-zero (ie the parent process) the second fork will be called and if that to returns non-zero the last will. So here all three forks are called in the original process - which means that it's called three times.
So first construct will make them five processes and the second will then for each process create three more. That means we will have 5*4 processes.
The reason you don't get consistent newlines is probably most due to printf buffering. The printf will only immediately print out a newline, and then write the rest of the data when it terminates, this means that they print the string in two step. We have 20 processes that first prints a newline and then prints "hello world" concurrently - the order between what the different processes prints cannot be guaranteed.
A minor possibility is the very fact that the actual printout aren't required to be atomic. That is one process may write "hell", and then a second which already written "hello " gets to write which may be "world" - which would result in "hellworld" instead.
Let's count how many times each fork is called. In this block there are 3 forks:
if(fork() || fork())
fork();
The 1st fork is called 1 time, by the first process.
The 2nd fork is called only 1 time, by the second process. (first process doesn't reach it)
The 3rd fork is called 2 times, by both first and second processes.
So, at this point you already have 5 processes.
For this block there are another 3 forks:
if(fork() && fork())
fork();
The 1st fork is called 1x 5 times. Here, the forked child process goes to printf directly.
The 2nd fork is called 1x 5 times. Still, the forked child process goes to printf.
The 3rd fork is called 1x 5 times.
So you have 20 in total.
This is much easier if you evaluate the two if constructs separately. Count the number of processes created in the first and multiply it by the number created in the second. The result is the total number of processes and the times the printf call is called.
(We are assuming fork calls will not fail.)
The first if statement is shows by this handy chart, where columns are forks, rows are processes.
forks - f1, f2, f3
processes - c0, c1, ... ,c4
xN - marks the creation of a process where N is the index of the created process
. - marks the process creation
_ - process exists and does nothing
(no character means the process doesn't exist at that point)
f1 f2 f3
c0 _ x1 _ x2 _
c1 . x3 x4 _
c2 . _
c3 . _ _
c4 . _
At this point 5 processes exist, 4 additional were created. The next chart shows the second if statement, but only for one process:
f1 f2 f3
c0 _ x1 x2 x3 _
c1 . _ _ _
c2 . _ _
c3 . _
This if statement, creates 3 additional processes, so 4 exist. But remember we had 5 processes before, not just one. So both if statements together create 5 x 4 processes, 20 in total.
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.
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.