Can't understand the value of a variable after fork() - c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include<sys/wait.h>
int main(){
int num = 2;
if (!fork()){
num++;
printf ("First: num = %d\n", num);
}else{
wait(NULL);
if (!fork()){
num++;
printf ("Second: num = %d\n", num);
}else{
wait(NULL);
num++;
printf ("Third: num = %d\n", num);
fflush(stdout);
exit(0);
}
}
fflush(stdout);
}
Can someone explain why num ends up being 3? I couldn't find a good explanation on fork().
What does (!fork()) even do??

fork is a Unix system call that duplicates a process. The program continues running twice, once in the parent process and once in a new child process. In the child process, fork returns zero, which is how the child can know it is the child. In the parent, it returns a process identification number for the child. (If an error occurs, it returns −1.)
This code:
if (!fork()){
num++;
printf ("First: num = %d\n", num);
says to create a child, then, in the child, increment num and print it. (In the child, fork returns zero, so !fork() is true.)
At this point, num is still 2 in the parent, because it was 2 when the fork was executed, and the num++ in the child incremented the child’s copy of it and did not affect the parent’s num.
In the else code:
wait(NULL);
if (!fork()){
num++;
printf ("Second: num = %d\n", num);
wait(NULL) says to wait for all children to finish execution, then create another child. That child does the same thing as above. Since it had 2 in num when it was created, the incremented produces 3, and the child prints 3.
The third piece of code does the same thing. The fflush calls are unnecessary.

Fork will create a new process based on the process you have created with your code. So when fork has created a new process it will return 0 for success.
And that is the reason for the output 3.
A detaied explanation how fork works can be found here: Fork-doc

Related

Parent code is called twice in multi process program in C

I have been learning about fork in c and i have this program:
int main(void) {
int i;
printf("Start program\n");
printf("This is parent process %d: %d\n", getpid(), i);
int pid = fork();
printf("%d ", pid);
if(pid == 0) {
printf("This is process %d: %d\n", getpid(), i);
}
return 0;
}
This is the output:
Start program
This is parent process 4467: 0
4578 Start program
This is parent process 4467: 0
0 This is process 4578: 0
I do not understand why the parent code is called twice.
stdout is buffered. See e.g. setvbuf(3).
You forgot to call fflush(3) before doing your fork(2). As a rule of thumb, you'll better do fflush(NULL) before any fork().
That could explain the observed behavior (because flushing happens later in both parent and child processes, e.g. at program exit or return from main in crt0). You might (on Linux) use strace(1) to understand more exactly what is happenning.
BTW, fork(2) could fail. You should handle that (that is, handle the pid == -1 (or pid<0) case...).

Another Fork() program in C

So I am continuing some more problems on Fork() and found some sample code on a website called geeksforgeeks. The following code segment:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
void forkexample()
{
int x = 1;
if (fork() == 0)
printf("Child has x = %d\n", ++x);
else
printf("Parent has x = %d\n", --x);
}
int main()
{
forkexample();
return 0;
}
Now I can see why the solution can be either Child has x = 2 and Parent has x = 0 but I am having some issues trying to visualize the tree. The big problem that I have visualizing this is that the first if statement is for the child process, so how would the tree look? Here is what I have come up with in terms of a visualization of this program.
Or would the main node on Level 0 be a Child node because of the order of the if statement coming first (this is a possibility but the else statement could come first as well as it is running concurrently).
Any help? Is this visualization correct or is there something I am missing?
Would appreciate the help , thank you.
No, your visualization is wrong.
After the fork you have TWO processes: Parent and Child. (PERIOD)
A single parent may spawn multiple children, and each may spawn children of their own. But after a single fork, the "tree" is two "nodes".
Not sure if you are trying to graph:
Processes over time, then YES, you are correct, one process has become two.
Process relationship, then NO, you should only have one parent, one child.
Execution path, I guess... at some point fork() is called, next thing you know, you have two processes executing the if() statement.
I don't see where the question is here..
The schema is good it's like this. Fork() creates a new process by duplicating the calling process. 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 (google). You must check the return value to be sure that you're in the child process which is running independently.
Try this :
#include <unistd.h>
int main()
{
pid_t p;
int x;
x = 1;
p = fork();
printf("pid = %d\n", p);
if (p == 0) {
printf("Child has x = %d and pid = %d\n", ++x, p);
sleep(1);
} else {
printf("Parent has x = %d and pid = %d\n", --x, p);
sleep(1);
}
}
They are executed at the same time because they are independant but the parent is primary at the ouput
Nicolas

Parent-Child relation using wait()-sleep() function call

Could anyone please help me to understand the flow of the below code:
/* Child Process creation using fork() */
#include<stdio.h>
#include<stdlib.h>
main(){
int i=0;
pid_t chp1,chp2,chp3;
chp1=fork();
if(chp1<0){
fprintf(stderr,"Child creation failed\n");
exit(1);
}
else if(chp1==0){
printf("Inside Child Process1,process id is %d\n", getpid());
printf("Value of i in Child process1 is %d\n", i);
i=i++;
printf("Value of i in child process1 after increment is %d\n", i);
sleep(10);
}
else{
chp2=fork();
if(chp2==0){
sleep(30);
printf("Inside Child Process2,process id is %d\n", getpid());
printf("Value of i in Child process2 is %d\n", i);
i=i+2;
printf("Value of i in child process2 after increment is %d\n", i);
sleep(40);
}
else{
wait(chp2);
printf("Inside Parent Process, value of pid1=%d pid2=%d\n", chp1,chp2);
printf("Value of i in Parent process is %d\n", i);
i=i+5;
printf("Value of i in Parent process, after increment is %d\n", i);
wait(chp1);
}
}
printf("Common Section, Value of i=%d\n", i);
}
---> the behaviour of the output should be like this:
First Child1(chp1) will execute its printf parts and also finish its execution.
Then Child2(chp2) will execute its printf parts and also finish its execution.
Then at last, parent process will execute its printf parts(as there is wait(chp2) before its printf parts, so it will wait for the execution of child2) and will finish its execution.
But, in output, I can see that
First Child1(chp1) will execute its printf parts and also finish its execution.
Parent process is executing its printf parts and then wait for child2.
Child2 completes its execution.
Parent completes its execution.
Below is the output:
[Rajim#rajim OS_Prog]$ ./a.out
Inside Child Process1,process id is 3291
Value of i in Child process1 is 0
Value of i in child process1 after increment is 1
Common Section, Value of i=1
Inside Parent Process, value of pid1=3291 pid2=3292 pid3=8605684
Value of i in Parent process is 0
Value of i in Parent process, after increment is 5
Inside Child Process2,process id is 3292
Value of i in Child process2 is 0
Value of i in child process2 after increment is 2
Common Section, Value of i=2
Common Section, Value of i=5
[Rajim#rajim OS_Prog]$
So could anyone please make me understand how the program is flowing?
Your call to wait() is wrong. wait() doesn't accept PID of the child argument (in single argument form), rather a pointer to an int to store the status.
Change the call to:
else{
int status;
wait(&status);
...
Remember that wait returns on a status change from any process. If you specifically want to wait for a process you should use waitpid():
else{
int status;
waitpid(chp2, &status, 0);
Also, the line in the first child:
i=i++;
invokes undefined behaviour in C.
To match your expected flow, you need to wait for ch1 before forking ch2. ch1 and the parent will run in parallell and there's no telling which one gets to execute first. Thus your checkpoint will have to be to let the parent continue executing after ch1 has exited.

Explain why fork causes the IF condition to behave differently.

I found this sample via a search.
At first glance I thought only the first fork() would be executed based on the IF condition, but actually both fork() calls get executed.
If the fork() command is changed to a simple boolean comparison like (x==10) then the IF conditions behave as expected.
What is it about the fork() that causes the IF condition to behave differently?
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
pid_t whichone, first, second;
int howmany;
int status;
int x = 0
if ((first=fork())==0) /* Parent spawns 1st child */
{
printf("Hiya, I am the first child nd my id is %d\n", getpid());
sleep(10);
exit(0);
}
else if (first == -1)
{
perror("1st fork: something went bananas\n");
exit(1);
}
else if ((second=fork())==0) /* Parent spawns 2nd child */
{
printf("Hiya, I am the second child and my id is %d\n", getpid());
sleep(15); /* Sleep 15 sec, then exit */
exit(0);
}
else if (second == -1)
{
perror("2nd fork: something went bananas\n");
exit(1);
}
printf("This is the parent\n");
howmany=0;
while (howmany < 2) /* Wait twice */
{
whichone=wait(&status);
howmany++;
if (whichone==first)
printf("First child exited ");
else
printf("Second child exited ");
if ((status & 0xffff)==0)
printf("correctly\n");
else
printf("uncorrectly\n");
}
return 0;
Here is the output when executed. Notice that both fork() calls are processed.
> runtThis
Hiya, I am the first child, and my id is 31204
Hiya, I am the second child, and my id is 31205
This is the parent
First child exited correctly
Second child exited correctly
The first if detects if its running in the child. If it isn't, but fork() didn't fail (i.e., it didn't return -1), it's in the original process, which can then continue and call fork() again.
Not sure what the confusion is about.
The fork() function duplicates the current process and then returns in both processes. So, effectively, the fork() function returns twice.
In the new process, fork() returns with the value 0, which causes the relevant branch that prints "I am the child" to be taken.
In the original process, fork() returns a non-zero value, indicating either failure (if it is negative) or the process id of the new process (if it is positive). As this value is non-zero, the branch is skipped to the next else if and that test is performed until one succeeds.
In the parent process, none of the if/else if tests will succeed, but each of the fork calls causes a new process to be created in which the corresponding test succeeds and that creates the effects you noticed.

When to call fork()?

I have two code samples here
#include<stdio.h>
int main()
{
int i = 0;
i++;
fork();
printf("i - %d, pid - %d, addr -%p\n",i,getpid(),&i);
return 0;
}
user#Ubuntu ~/Arena/c $ ./a
i - 1, pid - 6765, addr -0x7fffd892950c
i - 1, pid - 6766, addr -0x7fffd892950c
with my second program being
#include<stdio.h>
int main()
{
int i = 0;
i++;
printf("i - %d, pid - %d, addr -%p\n",i,getpid(),&i);
fork();
return 0;
}
user#Ubuntu ~/Arena/c $ ./b
i - 1, pid - 6772, addr -0x7fff39120f2c
Well as far as I know fork should create a COMPLETE copy of the parent program from top to bottom and execute it, if it is that way why is the position of fork() call making such a big difference ? Could some one explain why is the printf omitted in my second program ?
fork() creates a copy of the process, and continues executing both processes at the point you call fork().
So in your second example, your printf is executed before the fork when there is only one process.
Fork creates a complete copy of your program but execution continues from the point in which fork is called. Put printf after the fork and see what happens.
Usually a fork call will be followed by a check if fork returned the pid of the child or not. If it did, then your current running process is the parent which received the child's pid in order to be able to manage the child, if it didn't then your current running process is the child.
For further enlightenment, try:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int i = 0;
i++;
printf("A: i - %d, pid - %d, addr -%p", i, getpid(), &i);
fork();
printf("\nB: i - %d, pid - %d, addr -%p\n", i, getpid(), &i);
return 0;
}
The first printf() doesn't include a newline, so the output is held in memory. The second printf() includes newlines, so the output appears after the program has forked. You should see the same information in the two lines tagged A; you should see different information in the two lines tagged B.
In a single-threaded application, the parent and child processes are almost identical except for the PID, Parent PID, and the value returned by fork(). For the full details, see the POSIX specification of fork().

Resources