Hey I have a question regarding fork() and how it behaves in a for loop.
So following is asked from me:
Create a Parent Process that creates 10 child Processes each of them printing the actual i value in the for loop. Is this code correct?
int i;
for(i=0;i < 10;i++){
if(fork()==0){
print(i);
}
exit(0);
}
My understanding is that this snippet of code creates on every loop iteration a parent and a child, where the parent terminates directly and the child prints i;
So to have only one parent and 10 children each of them printing i, I should wrap the exit(0) like this:
int i;
int p;
for(i=0;i < 10;i++){
if((p=fork())==0){
print(i);
}
if(p > 0){
exit(0);
}
}
Can someone confirm or this if its right, or help me to get a better understanding if its wrong.
Thanks :)
The fork() call creates not a pair of new processes (parent, child), but leaves original process (parent) and creates one another process (child), so it "returns twice".
In your first snippet you really have only one parent. The only problem, it finishes on the very first iteration. :)
Look: i = 0, now we have only parent process (call it P).
P enters fork() and leaves it twice: in P (returning the PID of the child) and in the newly created child C0 (returning 0). Then, according to if statement, C0 prints 0, P does nothing. Then execution paths converges, and both P and C0 exit. Now we have no our processes at all.
Your second snippet's loop body can be rewritten as follows:
p = fork();
if (p == 0) {
print(i);
}
if (p > 0) {
exit(0);
}
Supposing fork() will not return negative number (error), these two if bodies are in fact just like then-else branches. They cause child process to print its number and old parent process to exit, so you got a waterfall of processes replacing one another in a sequence (most of them act exactly once as a child and then as parent).
You just need to rewrite it as such:
for(i = 0; i < 10; i++) {
p = fork();
if (p == 0) {
print(i);
exit(0);
}
// In fact, you should place waitpid(...) somewhere here,
// otherwise the child will become a so called zombie process
// after its termination.
// Only after parent termination they all will be
// finally recycled by init (PID 1) generally using up your system's
// resources for indefinite time
}
Now you have P that creates C0. C0 prints its number and immediately exits, while P just continues to the next loop iteration creating C1 that just like C0 prints its number and exits and so on. AFAIK it is what initially requested.
Please note that in real life you will have to somehow process the -1 return value that indicate some error in the fork() call (so in reality, in the second snippet rewritten by me there is a possibility that neither if statement will execute), I have omitted them for simplicity.
Related
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.
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).
I have a piece of code and I have to explain what is happening in the exit.
while(wait(NULL)>0)
The code is the following:
#include <stdio.h>
main() {
int n=1;
while(n<5) {
n=n+1;
if (fork() == 0)
n=n+2;
}
printf("%d %d %d\n", getpid(), getppid(), n);
while (wait(NULL) > 0);
}
When I execute the program the result shows 6 processes with 6 children and respective parents, while the condition while n < 5 has been met. If we cancel
while (wait(NULL) > 0);
then some children remain as zombies.
For example, when you are in the first child the output should be n = 4 instead I get n = 5 and outputs the results randomly without order.
I want to understand exactly the behaviour of while (wait (NULL)> 0)
If the current process have no child processes, wait(NULL) returns -1. Otherwise it waits until one of them exits, and returns it's process ID.
So while wait(NULL) > 0); loops until there are no more child processes, since when the last child exits, wait() will return -1 and the while loop terminates. (And wait() returning 0 should be an impossible condition too).
For example, when you are in the first child the output should be n =
4
Look at the code again: the last time the thread enters the while, n<5, but then it increments n in the while body before exiting the while loop and printing.
(UPDATE: I just noticed that in your sample code, the line n=n+1 is not indented. Maybe this is just an accident in entering the code, but it may be contributing to your confusion, since "n=n+1" does not look like it's happening in the while loop) Obviously the compiler doesn't care, but from the wording of your question, it sounds as if you do not realize that after the n=n+2, any thread where n<5 will loop back and increment n at least one more time. This is why no thread ever outputs 4 or less for n.
I want to understand exactly the behaviour of while (wait (NULL)> 0)
This is may not be direct answer to your problem, which is more related to fork than while(wait(NULL)>0), but might help other people (like me, who found your post when searching about this construct)
tl;dr: it waits for termination of all (direct) childs.
wait(ptr) on success returns (non-negative) pid of terminated child, and saves its status to int pointed by ptr (you can safely pass NULL, if you don't care). On "fail", -1 is returned and errno set appropriately.
In case of this loop, we don't consider no child processes as error, contrarily: it would be error if it didn't happen.
For extra error handling, one could write:
while(wait(NULL) != -1);
if(errno != ECHILD) {
perror("wait() error");
exit(1)
}
can anybody explain me working of fork in detail
#include<unistd.h>
#include<stdio.h>
int main ()
{
int i, b;
for (i = 0; i < 2; i++) {
fflush (stdout);
b = fork ();
if (b == -1) {
perror ("error forking");
}
else if (b > 0) //parent process
{
wait ();
printf ("\nparent %d", getpid ());
}
else
printf ("\nchild %d %d", getpid (), getppid ());
}
return 0;
}
its just i need to know that if fork have same code as parent then this for loop should never stop creating child processes (every child will have its own for loop)
Yes, each child will continue the loop, but the operative word here is "continue". The variable i will be inherited by the first child, and then increased, and this increased value is inherited by the second child, etc.
The same will happen in the children, as i is inherited and keeps it value from the parent process. This means that the loops will soon end in all children.
When you fork, the child process will continue with the same next instruction as the parent one and the values.
So it will stop one day ;)
Take a look at a similar question : fork in a for loop
Yes although the parent and child code are the same but in parent the fork returns the child process id hence in parents code, the variable b contains the child's pid whereas the in child, the fork returns 0, hence in the child code segment the variable b will have 0 and so does we can achieve different jobs even though forking will have same parent code in child.
In the next code:
int i = 1;
fork();
i=i*2;
fork();
i=i*2;
fork();
i=i*2;
printf("%d\n", i);
Why 8,8,8,8,8,8,8,8 is printed, and not 1,2,2,4,4,8,8,8? fork() duplicate the process, and print the i before each fork. What I miss?
Given the code shown, you should be seeing eight lots of 6 (you wrote i = i + 2; instead of i = i * 2; for the last computation.
Since each process follows the same code path, each process will produce the same result.
To get the result you expected, you'd have to track whether each fork() yielded the parent or child process:
int i = 1;
if (fork())
{
i=i*2;
if (fork())
{
i=i*2;
if (fork())
i=i*2; // + --> *
}
}
printf(|%d\n", i);
I'm assuming there are no problems with the fork() operation. It is also interesting to note that you could invert any or all of the conditions and end up with the same result.
Because fork continues to execute the code as it goes downwards. So each of the processes will run through the i = i * 2 each time as they spawn off more children. Making it what you get and not what you expected (i.e. it doesn't jump to the end of the block once forked).
Info on fork: http://www.csl.mtu.edu/cs4411/www/NOTES/process/fork/create.html
Each new process gets a copy of the stack of the parent, so immediately after calling fork(), both parent and child have the same value for i -- but they don't have the same stack, just a copy... so changing i's value in one process has no effect on the other.
If you want two parallel pieces of code to share the same memory, either use threads (and memory that's in the heap, not on the stack), or use an explicit shared memory region.