Exercise 4) Process System Calls
a) Fork , Exec & Wait System Call
b) Fork & Exec System Call
c) Create a process and compute factorial in child and Fibonacci in
parent
i)As separate code in child
ii)As executable file called in child.
iii) As executable called in Parent and a different executable
called in Child
d)
i)As separate code in child
#include <stdio.h>
#include <unistd.h>
int fact(int n) {
if (n == 0 || n == 1) {
return 1;
} else {
return n * fact(n - 1);
}}
int fib(int n) {
if (n <= 0) {
return 0;
} else if (n == 1) {
return 1;
} else {
return fib(n - 1) + fib(n - 2);
}}
int main(int argc, int *argv[]) {
int n;
printf("Enter n\n");
scanf("%d",&n);
pid_t pid=fork();
if (pid == 0) {
printf("Child process ID: %d\n", getpid());
printf("Factorial %d\n",fact(n));
}
else{
printf("Parent process ID: %d\n", getpid());
printf("Fibonacci %d\n", fib(n));
}
return 0;}
ii)As executable file called in child.
Factorial :
#include<stdio.h>
#include<stdlib.h>
int fact(int n) {
if (n == 0 || n == 1) {
return 1;
} else {
return n * fact(n - 1);
}
}
void main(int argc, char *argv[])
{
int n=atoi(argv[1]);
printf("%d\n",fact(n));
}
Fibonacci:
#include<stdio.h>
#include<stdlib.h>
int fib(int n) {
if (n <= 0) {
return 0;
} else if (n == 1) {
return 1;
} else {
return fib(n - 1) + fib(n - 2);
}
}
void main(int argc, char *argv[])
{
int n=atoi(argv[1]);
printf("%d\n",fib(n));
}
iii) As executable called in Parent and a different executable
called in Child
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid=fork();
if (pid == 0) {
printf("Child process ID: %d\n", getpid());
char *a[] = {"./factorial","7", NULL};
execvp(a[0],a);
}
else{
printf("Parent process ID: %d\n", getpid());
char *a[] = {"./fibonacci ","7", NULL};
execvp(a[0],a);
}
return 0;
}
d) Program to create four processes (1 parent and 3 children)
where they
terminates in a sequence as Follows:
i. Parent process terminates at last
ii. First child terminates before parent and after
second child.
iii. Second child terminates after last and before first
child.
iv. Third child terminates first.
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t c1=fork();
pid_t c2,c3;
if (c1 == 0) {
printf("Child process 1 ID: %d\n", getpid());
}
else{
printf("Parent process ID: %d\n", getpid());
c2=fork();
c3=fork();
if(c3==0)
printf("Child process 3 ID: %d\n", getpid());
if(c2==0)
printf("Child process 2 ID: %d\n", getpid());
}
if (c3 != 0 && c2 != 0 && c1 != 0){
kill(c3);
printf("Killed child 3\n");
sleep(1);
kill(c2);
printf("Killed child 2\n");
sleep(1);
kill(c1);
printf("Killed child 1\n");
sleep(1);
kill(getpid());
printf("Killed parent\n");
}
return 0;
}
e) Create Zombie and orphan process and analyse its behaviour
and discuss
how to avoid that.
Ref: https://www.javatpoint.com/what-is-zombie-process
Zombie Process:
A zombie process is one that has completed execution but remains in the process table, as its
parent process hasn't collected its exit status via wait() or waitpid() calls. These undead
processes consume resources and may lead to exhaustion if not handled properly.
How to avoid Zombie
Reaping: The parent process should use the wait() or waitpid() system calls to retrieve
the exit status of its child processes then the OS removes the entry of the zombie process
from the process table.
Don’t use many process: Ensure that you don't create more child processes than needed then
it can lead to a higher chance of zombie processes.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t pid = fork();
if (pid == 0) {
printf("Child process ID: %d start\n", getpid());
sleep(2);
printf("Child process ID: %d end\n", getpid());
exit(0);
} else {
printf("Parent process ID: %d waits\n", getpid());
sleep(4);
printf("Parent process ID: %d completed\n", getpid());
}
return 0;
}
When you run this code, it creates a child process that simulates some work and then exits.
The parent process waits for 4 seconds and then proceeds. During the waiting period, the
child process becomes a zombie, as its exit status has not been collected by the parent
process.
Orphan Process:
An orphan process persists post-parent termination, often adopted by the init process (PID 1)
to prevent zombie status, ensuring continuous execution and resource use.
e) Modify the previous program to avoid orphans
Cue:
Managing Child Processes: Make sure the parent process waits for its child processes to
complete before it exits.
Using Signals: You can use signals to notify parent processes about certain events.
Double Fork: If you want to detach a child process from its parent, you can use a double
fork. This technique involves creating a new child process from the initial child process. The
new child process is then adopted by the init process. This way, the initial child process can
terminate without creating an orphan.