while(wait(NULL) > 0) doubts with result - c

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

Related

How can the multi-core cpu run the program interleaved?

The output of the program are not obviously contents from the printf()s in teh code. Instead it looks like characters in irregular sequence. I know the reason is because the parent process and child process are running
at the same time, but in this program I only see pid=fork(), which I think means pid is only the id of child process.
So why can the parent process print?
How do the two processes run together?
// fork.c: create a new process
#include "kernel/types.h"
#include "user/user.h"
int
main()
{
int pid;
pid = fork();
printf("fork() returned %d\n", pid);
if(pid == 0){
printf("child\n");
} else {
printf("parent\n");
}
exit(0);
}
output:
ffoorrkk(()) rreettuurrnende d 0
1c9h
ilpda
rent
I focus my answer on showing how the observed output can result from the shown program. I think that it will already clear things up for you.
This is your output.
I edited it to use a good guess of what is parent (p) and child (c):
ffoorrkk(()) rreettuurrnende d 0\n
cpcpcpcpcpcpcpcpcpcpcpcpccpcpcppccc
1 c9h\n
pccpcpp
ilpda\n
ccpcpcc
rent
pppp
If you only use the chars with a "c" beneath, you get
fork() returned 0
child
If you only use the chars with a "p" beneath, you get
fork() returned 19
parent
Split that way, it should match what you know about how fork() works.
Comments already provided the actual answer to the three "?"-adorned questions in title and body of your question post.
Lundin:
It creates two processes and they are executed just as any other process, decided by the OS scheduler.
Yourself:
each time fork() is called it will return twice, the parent process will return the id of child process, and child process will return 0
Maybe for putting a more obvious point on it:
The parent process receives the child ID and also continues executing the program after the fork().
That is why the output occurs twice, similarily, interleaved, with differences in PID value and the selected if branch.
Relevant is also that in the given situation there is no line buffering. Otherwise there would be no character-by-character interleaving and everthing would be much more readable.

Understanding fork() in for loop and usage of exit()

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.

Parent trying to read children exit status (or return value), fork and wait

I'm confused. Supposedly, basing on man, and many other sources, like this:
Return code when OS kills your process
wait(&status) should make it possible for me to get the exit status or return value of a child process?
Those 2 snippets of code, should allow me to see the exit value of it's child, and then print it.
child process function:
int childFunction(char in[],char logPath[]){
FILE *logFile= fopen( logPath, "a" );
if(logFile==NULL)
return 1;
int c=system(in);
fclose(logFile);
return(c);
}
and main:
{...some unimportant code before this}
result= fork();
if(result==0){
exit(childFunction(inLine,logPath));
}
else if(result>0){
int status=0;;
int c=(int)waitpid(-1,&status,0);
printf("a:%d b:%d\n",status, WIFEXITED(status));
else
return -1;
i=0;
I tried going with wait, sleeping for some time, exiting, returning, and read man page a few times. There either is a basic error in my understanding of this function, or after 4 hours of looking I simply no longer can see it.
SOLVED
For some reason, which i absolutely do not understand, if you change the return(c) in childFunction to if(c!=)return(1);else return(0) it will work. No idea why.
SOLVED 2
Okay, now I think I know why. See, it appears that either return call, or wait, reduces status to 8 most significant bits (256). What does that mean? That means, if you send normal int, the first bits are used, while the last 8 are discarded. At the same time, when I specify return (1) compiler automatically "shortens" the int to short int. Solution is to either return a short number, or do it like I did in previous "Solved" comment.
the problem is you are not waiting for the child to exit
int c=(int)waitpid(-1,&status,WNOHANG);
Here the parent process checks if the child process has exited and if the child has not exited it returns.
In the above case, since you are opening a file in child process,there is a greater probability that there is a IO wait at child and so the parent process would be executed.
Now the parent process would check the status and since WNOHANG is used it will not be blocked at the waitpid and it continues and this is the reason you are not getting the correct status
I would suggest you use
int c=(int)waitpid(&status);

Fork() command issue

While going thorough fork() command i got struck with a question .
how many no.of processes are created by the end of 12th second, if
time starts from 0th second? Process id's start from 0.
Pseudo code
while(true)
{
sleep 1second;
if( getpid() % 2 == 0 )
{
fork();
printf("Hello\n");
}
}
when i run above code on my system it is not showing output on konsole. Is no . of process at end of 12 sec is dependent on OS ?Need suggestion as i am not good in fork()
Since when do process IDs "start at 0"? Not even when the system boots; the first process has the id 1 :-)
You're only fork()ing when your own process ID is even; so if it happens to be odd then nothing will happen... which means that if you run the program several times, sometimes it will do something and sometimes it won't.
Add this after your printf:
fflush(stdout);
But you have a fundamental problem with your logic. fork() returns 0 in the child, and the child pid in the parent. You don't check, so both the parent and the child continue doing the loop, which happens again, and again, and again, forever. You need to change the loop body to this:
if(fork() == 0)
{
printf("Hello!\n");
fflush(stdout);
}

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