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

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.

Related

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

#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

fork: child process doesn't stay in an infinite loop

#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = fork();
printf("pid : %d\n", getpid());
if( pid == 0)
{
printf("child: pid : %d \n", getpid());
while(1);
}
else
{
printf("parent: pid : %d \n", getpid());
//while(1);
}
}
In the above code snippet inside if statement if we put while(1), it doesn't remains blocked and when enter key is pressed program is exited, but in case of parent if we put while(1), parent remains blocked until we give ctrl+c. Please clarify this behaviour of child.
In the above code snippet inside if statement if we put while(1), it doesn't remains blocked
The child process doesn't exit actually; it just becomes an orphan process because its parent exits. The orphaned chuld process will be adopted by the init process of your system. You can see it via ps command.
But if you put the while(1); in the parent process it remains blocked.
Basically whichever process has while(1); infinite loop, it's still running. When parent exits you get the prompt back and the child becomes orphan. But the child process is still running.
In general, you need to wait(2) for the child process in the parent process to reap child processes.

Using switch statements to fork two processes

I'm taking an intro to C course and I've become a bit stumped on the first assignment. We've been tasked with creating a parent processes and two child processes. All of the examples the text has shown us so far involve switch statements with one parent and one child. I'm a bit confused about how to translate this into one parent and two child processes. Here is what I have so far:
#include <stdio.h>
int main() {
int i, pid, status;
pid = fork();
switch(pid) {
case -1:
/* An error has occurred */
printf("Fork Error");
break;
case 0:
/* This code is executed by the first parent */
printf("First child process is born, my pid is %d\n", getpid());
printf("First child parent process is %d\n", getppid());
for (i=1; i<=10; i++)
printf("First child process, iteration: %d\n", i);
printf("First child dies quietly.\n");
break;
default:
/* This code is executed by the parent process */
printf("Parent process is born, my pid is %d\n", getpid());
wait(&status);
printf("Parent process dies quietly.\n");
}
}
This works perfect for this one process:
Parent process is born, my pid is 10850
First child process is born, my pid is 10851
First child parent process is 10850
First child process, iteration: 1
First child process, iteration: 2
First child process, iteration: 3
First child process, iteration: 4
First child process, iteration: 5
First child process, iteration: 6
First child process, iteration: 7
First child process, iteration: 8
First child process, iteration: 9
First child process, iteration: 10
First child dies quietly.
Parent process dies quietly.
Essentially I just need to do the same thing with a second process... something like:
printf("Second child process is born, my pid is %d\n", getpid());
printf("Second child parent process is %d\n", getppid());
for (k=1; k<=10; k++)
printf("Second child process, iteration: %d\n", i);
printf("Second child dies quietly.\n");
break;
But I'm just not sure how to get there from what I have so far. Am I approaching this correct way? Is there a better method I should be using? Thanks so much.
There is a general rule. When you use fork(2) you should always handle the three cases below:
fork gave 0, you are in the child process
fork gave a positive pid_t, you are in the parent process
fork failed and gave -1
People (newbies) sometimes tend to forget the last (failure) case. But it does happen, and you might easily test that case by using setrlimit(2) with RLIMIT_NPROC in your grand-parent process to lower the limit on processes, often that grand-parent process is your shell (e.g. using ulimit Bash builtin with -u).
Now, how to handle the three cases is a matter of coding style. You can use switch but you can use two if. Your code uses a switch and is right to do so.
As a general rule, most system calls (listed in syscalls(2)) can fail, and you almost always need to handle the failure case (see errno(3) and use perror(3)).
Read also Advanced Linux Programming (freely downloadable).
I'm a bit confused about how to translate this into one parent and two child processes.
The fork system call is creating (on success) exactly one child process. So if you need two children, you should call it twice (and test failure on both calls) in a row. If you need one child and one grand child, you should do the second fork only when the first one gave 0. Of course you need to keep both (successful and positive) pid_t -e.g. in two variables- returned by your two calls to fork.
To avoid zombie processes, every successful fork should later have its wait system call (e.g. waitpid(2) or wait or wait4(2) or wait3). Where you do that wait depends if you want to have both children running at the same time or not. But every successful fork should have a corresponding successful wait call.
Read also signal(7) (and signal-safety(7)) about SIGCHLD if you want to be asynchronously notified about child processes change - notably termination. A common way is to install a SIGCHLD signal handler (e.g. using sigaction(2) or the old signal(2)) which just sets some global volatile sigatomic_t flag and test then clear that flag in convenient place in your code (e.g. in some event loop using poll(2)).
NB: notice that fork is not about C programming (fork is not defined in the C11 standard n1570 or its predecessor C99). It is a POSIX and Linux thing. Windows or z/OS or an Arduino microcontroller don't have it natively, but are programmable in some standard C.
You can put fork and switch case in loop so that it forks multiple processes, something like below:
Edit: You can remove if condition to call wait after each fork, alternately if you want to launch all children then wait for them to terminate, in each iteration you can collect pid of each child (in parent process ie in default switch case) in an array and in last iteration call waitpid in a loop(for each pid) to ensure each child process has exited
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
int i, pid, status;
int j = 0;
int numChildren = 2;/*Change it to fork any number of children*/
for(j = 0;j< numChildren;j++)
{
pid = fork();
switch(pid) {
case -1:
/* An error has occurred */
printf("Fork Error");
break;
case 0:
/* This code is executed by the first parent */
printf("First child process is born, my pid is %d\n", getpid());
printf("First child parent process is %d\n", getppid());
for (i=1; i<=10; i++)
printf("First child process, iteration: %d\n", i);
printf("First child dies quietly.\n");
exit(0);/*Otherwise it will fork its own child*/
break;
default:
/* This code is executed by the parent process */
printf("Parent process is born, my pid is %d\n", getpid());
if(j == (numChildren - 1))/*You can remove this condition to wait after each fork*/
{
wait(&status);
printf("Parent process dies quietly.\n");
}
}
}
}
To make 2 child you call fork()2x. So call fork with 2 different variable and then wait for them both.

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.

Fork call working

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.

Resources