Fork_Wait_Exec_Code
Fork_Wait_Exec_Code
Chain of Processes
................................................................................
Example 1:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
int pid;
int n=4;
if (pid > 0) {
// Print the parent process
printf("Parent process ID is %d\n", getpid());
break;
}
else {
// Print the child process
printf("Child process ID is %d\n", getpid());
}
}
return 0;
}
Output :
Parent process ID is 8678
Child process ID is 8679
Parent process ID is 8679
Child process ID is 8680
Parent process ID is 8680
Child process ID is 8681
Example 2:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
int n = 4;
if (child_pid == -1) {
// Fork failed
perror("fork");
}
if (child_pid == 0) {
// Child process
printf("Child %d with PID %d is created. Parent PID %d\n", i ,
getpid(), getppid());
}
else {
// Parent process
printf("Parent PID: %d\n", getpid());
// Wait for the child process to finish before creating the next one
wait(NULL);
break; // Prevent the parent from creating additional children
}
}
return 0;
}
Output:
Parent PID: 15385
Child 1 with PID 15386 is created. Parent PID 15385
Parent PID: 15386
Child 2 with PID 15388 is created. Parent PID 15386
Parent PID: 15388
Child 3 with PID 15389 is created. Parent PID 15388
Example 3:
Creates a chain of n processes, where n is a command line argument.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main (int argc, char *argv[])
{
pid_t childpid = 0;
int i, n;
if (argc != 2)
{/* check for valid number of
command-line arguments */
fprintf(stderr, "Usage: %s processes\n", argv[0]);
return 1;
}
n = atoi(argv[1]);
for (i = 1; i < n; i++)
if (childpid=fork())
break;
fprintf(stderr, "i:%d process ID:%ld parent ID:%ld child ID:%ld\n", i,
(long)getpid(), (long)getppid(), (long)childpid);
return 0;
}
------------------------------------------------------------------
Fan of Processes
Example 1:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
for (int i = 1; i < 4; i++) {
if (fork() == 0) {
printf("child pid %d from the parent pid %d\n", getpid(),
getppid());
exit(0);
}
}
}
Output:
child pid 2833 from the parent pid 2832
child pid 2834 from the parent pid 2832
child pid 2835 from the parent pid 2832
Example 2:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
int n = 4; // Number of child processes to create
if (child_pid == -1) {
// Fork failed
perror("Fork failed");
return 1;
} else if (child_pid == 0) {
// Child process
printf("Child process %d with ID: %d and Parent ID: %d\n", i,
getpid(), getppid());
return 0;
}
Output:
Parent process ID: 5800
Child process 1 with ID: 5801 and Parent ID: 5800
Child process 2 with ID: 5802 and Parent ID: 5800
Child process 3 with ID: 5803 and Parent ID: 5800
All child processes have completed.
Example 3:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
Explain what happens when you replace the test (childpid = fork()) <= 0 of the
previous program with (childpid = fork()) == -1 ?
Draw a suitable diagram labelling the circles with the actual process.
--------------------------------------------------------------------------------
--
................................................................................
..
Example 1 :
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
pid_t id = fork();
if(id==0)
{
printf("I am child and my pid is :%d\n", getpid());
sleep(5);
exit(0);
}
printf("Before wait call \n");
pid_t waitr = wait(NULL); //return childid
printf("Parent executed wait and wait return :%d\n",waitr);
}
Example 2 :
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
int status;
pid_t id = fork();
if(id==0)
{
printf("I am child and my pid is :%d\n", getpid());
pid_t waitr = wait(NULL);
if(waitr==-1){
perror("Error is :");
}
exit(0);
}
printf("I am Parent\n");
//printf("Status=%d\n",status);
}
Example 3:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
int status;
pid_t id = fork();
if(id==0)
{
printf("I am child and my pid is :%d\n", getpid());
sleep(5);
exit(0); // Normally Terminated
}
printf("Before wait call \n");
pid_t waitr = wait(&status);
printf("Parent executed wait and wait return\n",waitr);
15......8 | 7......0
XXXXXXXX | XXXXXXXX
exitStatus | unused
exit(0) status=0
15......8 | 7......0
00000000 | 00000000
exitStatus | unused
exit(1) status=256
15......8 | 7......0
00000001 | 00000000
exitStatus | unused
00000000 | 00001001
unused | termination signal
15......8 | 7 ......0
unused | 1 termination signal
|
|-----> core dump flag
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
int status;
pid_t id = fork();
if(id==0)
{
printf("I am child and my pid is :%d\n", getpid());
int *p=NULL;
*p=7;
exit(1);
}
printf("Before wait call \n");
pid_t waitr = wait(&status);
printf("Parent executed wait and wait return\n",waitr);
printf("Status=%d\n",status);
}
--------------------------------------------------------------------------------
------
Example 1 :
int main()
{ /* PID of child 3425 */
pid_t childpid,waitreturn; /* PID of parent 3424 */
childpid = fork();
if(childpid == 0)
{
printf("Process ID=%ld\n",(long)getpid());
}
waitreturn=wait(NULL);
if (childpid != waitreturn) // 0 != -1 True for child
{
printf("Return value of fork=%ld\n",(long)childpid);
printf("Process ID=%ld\n",(long)getpid());
printf("Return value of wait=%d\n",waitreturn);
}
return 0;
}
Example 2 :
int main()
{ /* PID of child 3425 */
pid_t childpid,waitreturn; /* PID of parent 3424 */
childpid = fork();
if(childpid == 0)
{
printf("Process ID=%ld\n",(long)getpid());
}
waitreturn=wait(NULL);
if (childpid == waitreturn) // True for Parent process
{
printf("Return value of fork=%ld\n",(long)childpid);
printf("Process ID=%ld\n",(long)getpid());
printf("Return value of wait=%d\n",waitreturn);
}
return 0;
}
Example 3 :
int main()
{ /* PID of child 3425 */
pid_t childpid; /* PID of parent 3424 */
childpid = fork();
// Code executed by both parent and child processes
if(childpid == 0)
{
printf("Process ID=%ld\n",(long)getpid()); // Code executed by the child
process
}
if (childpid == wait(NULL)) // Code executed by the parent process
printf("Return value of fork=%ld\n",(long)childpid);
printf("Process ID=%ld\n",(long)getpid());
}
return 0;
}
In the child process (if (childpid == 0)), it prints the Child Process ID using
getpid().
In the parent process (else part), it waits for the child process to terminate
using wait(NULL).
The return value of wait() is the process ID of the terminated child process,
which is printed.
Output :
Child Process ID=3425
Return value of fork=3425
Parent Process ID=3424
Example 4 :
int main()
{ /* PID of child 3425 */
pid_t childpid; /* PID of parent 3424 */
childpid = fork();
if(childpid == 0)
{
printf("Process ID=%ld\n",(long)getpid());
}
if (childpid != wait(NULL))
printf("Return value of fork=%ld\n",(long)childpid);
printf("Process ID=%ld\n",(long)getpid());
}
return 0;
}
................................................................................
......
wait & macro operation
POSIX specifies six macros for testing the childâs return status. Each takes
the status value returned by a child to wait or waitpid as a parameter.
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
int status;
pid_t id = fork();
if(id==0)
{
printf("I am child and my pid is :%d\n", getpid());
exit(1);
}
printf("Before wait call \n");
pid_t waitr = wait(&status);
printf("Parent executed wait and wait return\n",waitr);
printf("Status=%d\n",status); // status = 256
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
int status;
pid_t id = fork();
if(id==0)
{
printf("I am child and my pid is :%d\n", getpid());
sleep(50);
exit(1);
}
printf("Before wait call \n");
pid_t waitr = wait(&status);
printf("Parent executed wait and wait return\n",waitr);
printf("Status=%d\n",status);
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
int status;
pid_t id = fork();
if(id==0)
{
printf("I am child and my pid is :%d\n", getpid());
sleep(50);
exit(1);
}
printf("Before wait call \n");
pid_t waitr = wait(&status);
printf("Parent executed wait and wait return\n",waitr);
printf("Status=%d\n",status);
printf("status by macro:%d\n",WSTOPSIG(status));
}
It is not possible for the parent to retrieve the signal number during which the
child process has stopped the execution (SIGSTOP(19), SIGTSTP(20)).
Parent wonât be able to get the notification when a stopped child was resumed
by the delivery of a signal (SIGCONT(18), SIGCHLD(17)).
Parent can only wait for first child that terminates. It is not possible to wait
for a particular child.
It is not possible for a non blocking wait so that if no child has yet
terminated, parent get an indication of this fact.
................................................................................
............................................................
waitpid
The waitpid function lets us wait for one particular process, whereas the wait
function returns the status of any terminated child.
The waitpid function provides a nonblocking version of wait. There are times
when we want to fetch a childâs status, but we donât want to block.
The waitpid function provides support for job control with the WUNTRACED and
WCONTINUED options.
#include <sys/wait.h>
a pid
a pointer to a location for returning the status
a flag specifying options.
First Parameter :
Note :
int status;
wait(&status) or waitpid(-1, &status, 0);
Third parameter :
can be zero , options = 0 waitpid waits until the child change state.
or
can be the bitwise inclusive OR of the constants: WNOHANG, WUNTRACED,and
WCONTINUED
Example 1 :
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
int main()
{
pid_t cpid;
pid_t cpid2;
pid_t ret_pid;
int status = 0;
cpid = fork();
if(cpid == -1)
exit(-1); /* terminate child depending on use case*/
if(cpid == 0){
printf("\nchild-1 executing its pid = (%d)\n",getpid());
sleep(10);
printf("Child1 exited\n");
exit(0);
}
else{
cpid2 = fork();
if(cpid2 == -1){
exit(-1);
}
if(cpid2 == 0){
printf("\nchild-2 executing its pid = (%d)\n",getpid());
sleep(5);
printf("Child2 exited\n");
exit(1);
}
return 0;
}
Example 2 :
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
#include <errno.h>
int main()
{
pid_t cpid;
pid_t cpid2;
pid_t ret_pid;
int status = 0;
cpid = fork();
if(cpid == -1)
exit(-1); /* terminate child depending on use case*/
printf("Child1 exited\n");
exit(0);
}
else{/* This is parent process*/
printf("\n Parent executing before wait() Parent pid is (%d)\
n",getpid());
ret_pid = waitpid(80, &status, WNOHANG);
//ret_pid = waitpid(cpid, &status, 0);
if (ret_pid == -1){
perror("Error is:");
printf("\n waitpid returned error (%d)\n",errno);
}
printf("\n cpid returned is (%d)\n",ret_pid);
printf("\n status is (%d)\n",status);
return 0;
}
#if 0
refer to below for details on errno
man errno
#endif
Example 3 :
//Using WNOHANG : Nonblocking version of wait. when we want to fetch a childâs
status, but we donât want to block.
Parent is not waiting for that child and but parent is execute other line after
waitpid.
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
int main()
{
pid_t cpid;
pid_t cpid2;
pid_t ret_pid;
int status = 0;
cpid = fork();
if(cpid == -1)
exit(-1); /* terminate child depending on use case*/
if(cpid == 0){
printf("\nchild-1 executing its pid = (%d)\n",getpid());
sleep(10);
printf("Child1 exited\n");
exit(0);
}
else{
cpid2 = fork();
if(cpid2 == -1){
exit(-1);
}
if(cpid2 == 0){
printf("\nchild-2 executing its pid = (%d)\n",getpid());
sleep(5);
printf("Child2 exited\n");
exit(1);
}
do(){
ret_pid = waitpid(cpid2, &status, WNOHANG);
printf("Parent is waiting.......\n");
sleep(10);
} while(ret_pid==0);
perror("error is:");
printf("\n cpid returned is %d\n", ret_pid);
printf("Status=%d\n",status);
return 0;
}
Example 4:
using WNOHANG|WUNTRACED|WCONTINUED
.....................................
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
int main()
{
pid_t cpid;
pid_t cpid2;
int status = 0;
cpid = fork();
if(cpid == -1)
exit(-1); /* terminate child */
if(cpid == 0){
printf("\nfirst child executing its pid = (%d)\n",getpid());
sleep(20);
printf("Child pid = %d\n", getpid());
exit(1);
}
else{
cpid2 = fork();
if(cpid2 == 0){
printf("\nsecond child executing its pid = (%d)\n",getpid());
sleep(20);
printf("Child pid = %d\n", getpid());
exit(1);
}
printf("\n Parent executing before wait()\n");
while(1)
{
pid_t id2 = waitpid(cpid, &status, WNOHANG|WUNTRACED|WCONTINUED);
printf("status == %d\n",status);
sleep(1);
if(id2==-1)
{break;}
if(id2>0){
//cpid = wait(&status);
if(WIFEXITED(status)){
printf("The exit status set %d \n", WEXITSTATUS(status));
}
else if (WIFSIGNALED(status)){
printf("The termination signal is %d \n", WTERMSIG(status));
}
else if (WIFSTOPPED(status)){
printf("The stopped signal is : %d \n",WSTOPSIG(status));
}
else if (WIFCONTINUED(status))
printf("The prosess is resume\n");
}
}
}
printf("The parent process completed .......\n");
return 0;
}
--------------------------------------------------------------------------------
--------------------------
ZOMBIE
If the child dies first, the kernel empties the process address space but
retains the process table entry. The child is said to be in a zombie state.
Example 1:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t id;
printf("Parent Process : Executed by parent process before fork() - PID =
(%d)\n",getpid());
id = fork(); // from this point of code, the child and parent process both
execute
if (id < 0 ){
printf("\nfork failed\n");
exit(-1);
}
if(id > 0){ /* Parent process*/
sleep(30);
}else
{ /* Child process*/
exit(0);
}
return 0;
}
Example 2:
/*
Demonstrate Zombie process
run command on terminal - ps aux | grep Z
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t id;
printf("Parent Process : Executed by parent process before fork() - PID =
(%d)\n",getpid());
id = fork(); // from this point of code, the child and parent process both
execute
if (id < 0 ){
printf("\nfork failed\n");
exit(-1);
}
if(id > 0){ /* Parent process*/
sleep(15);
printf("\nParent Process: I have created child process withID = (%d)\
n",id);
printf("\n Paren process exited\n");
}else
{ /* Child process*/
sleep(5);
printf("\nchild process id is (%d)\n",getpid());
printf("\nThe creator of child process is (%d)\n",getppid());
}
return 0;
}
Look into the line that contains defaunct. It is the Zombie with process state
code Z
man ps
to read process state information under the heading PROCESS STATE CODES
--------------------------------------------------------------------------------
----------------------------
ORPHAN
When the parent dies first, the child becomes an orphan since the parent is not
just there to pickup the childâs exit status.
The kernel clears the process table slot of the parent, but before doing so, it
checks whether there are any process spawned by the parent that are still alive.
When it finds one , it makes init/ systemd its parent by changing PPID field of
the child.
Example 1:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t id;
printf("Parent Process : Executed by parent process before fork() - PID =
(%d)\n",getpid());
id = fork();
if (id < 0 ){
printf("\nfork failed\n");
exit(-1);
}
if(id > 0){ /* Parent process*/
exit(0);
}else
{ /* Child process*/
sleep(60);
}
return 0;
}
Open two terminal windows. Run the previous slide code in one terminal. On the
other terminal run the command
Observe the process id (PID) and parent id (PPID) of the child and parent.
Example 2:
/*
Demonstrate Orphan process (A Process that does not have a parent)
(Reparenting : Finding another parent for the process. Init process becomes
parent)
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t id;
printf("Parent Process : Executed by parent process before fork() - PID =
(%d)\n",getpid());
id = fork(); // from this point of code, the child and parent process both
execute
if (id < 0 ){
printf("\nfork failed\n");
exit(-1);
}
if(id > 0){ // Parent process, killing before child executes
printf("\nParent process exited\n");
return (0);
}else
{ // Child process
printf("\nChild process executing\n");
sleep(10);
printf("\nI am child process, id value is (%d)\n",id) ;
printf("\nchild process id is (%d)\n",getpid());
}
return 0;
}
--------------------------------------------------------------------------------
------------------------------
exec Family of System Calls
The exec family of functions replaces the current process image with a new
process image.
The fork function creates a copy of the calling process, but many applications
require the child process to execute code that is different from that of the
parent.
The exec operation replaces the entire address space(text, data, and stack) with
that of the new process.
Since the stack is also replaced, the call to exec family of functions donot
return unless it results in an error.
The child executes ( with an exec function) the new program while the parent
continues to execute the original code.
All exec functions return -1 and set errno if unsuccessful.
execl(argument list)
execle(argument list)
execlp(argument list
execv(argument list)
execve(argument list)
execvp(argument list)
The path parameter to execl is the pathname of a process image file specified
either as a fully qualified pathname or relative to the current directory.
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg0, ... /*, char *(0) */);
int execle (const char *path, const char *arg0, ... /*, char *(0), char *const
envp[] */);
int execlp (const char *file, const char *arg0, ... /*, char *(0) */);
int execv(const char *path, char *const argv[]);
int execve (const char *path, char *const argv[], char *const envp[]);
int execvp (const char *file, char *const argv[]);
Example 1 : execl
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
printf("\n I am main process pid = (%d)\n",getpid());
execl("./np","arg1","arg2","arg3",NULL);
return 0;
}
#include<stdio.h>
#include<unistd.h>
gcc np.c -o np
gcc mp.c -o mp
./mp
Example 2 : execl
Main Program :
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
int main()
{
pid_t cpid;
int status = 0;
int num = 5;
cpid = fork();
if(cpid == -1)
exit(0); /* terminate child */
if(cpid == 0){
printf("\nBefore exec\n");
execl("./program2","arg1","arg2",NULL);
printf("\n line is not printed\n");
}
else{
printf("\n Parent executing before wait(), child process created by
parent is = (%d)\n",cpid);
cpid = wait(&status); /* waiting for child process to exit*/
printf("\n wait() in parent done\nParent pid = %d\n", getpid());
printf("\n cpid returned is (%d)\n",cpid);
printf("\n status is (%d)\n",status);
}
return 0;
}
New Program :
#include<stdio.h>
#include<unistd.h>
Example 3 : execv
Main Program :
/*
Demo to use execv()
*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
printf("\n Main program p1.c\n");
//A null terminated array of character pointers
char *args[]={"arg1","arg2","arg3",NULL};
execv("./p2",args);
printf("\nThis line is not printed\n");
return 0;
}
New Program :
#include<stdio.h>
#include<unistd.h>
return 0;
}
Example 4 : execv
Main Program :
New Program :
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
exit(0);
}
--------------------------------------------------------------------------------
------------
Solved Some Problems
Example 1:
P
/ | \
c1 c2 c3
/ \
c4 c5
|
c6
|
c7
Develop a C code to create the following process tree. Display the process ID,
parent ID and return value of fork() for each process.
Code :
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
// Process p creates c1, c2, c3
pid_t c1, c2, c3;
c1 = fork();
if (c1 == 0) {
// Process c1
printf("c1: PID=%d, PPID=%d, Fork()=%d\n", getpid(), getppid(), 0);
exit(0);
}
c2 = fork();
if (c2 == 0)
{
// Process c2 creates c4, c5
printf("c2: PID=%d, PPID=%d, Fork()=%d\n", getpid(), getppid(), 0);
c4 = fork();
if (c4 == 0) {
// Process c4
printf("c4: PID=%d, PPID=%d, Fork()=%d\n", getpid(), getppid(), 0);
exit(0);
}
c5 = fork();
if (c5 == 0) {
// Process c5 creates c6
printf("c5: PID=%d, PPID=%d, Fork()=%d\n", getpid(), getppid(), 0);
pid_t c6 = fork();
if (c6 == 0) {
// Process c6 creates c7
printf("c6: PID=%d, PPID=%d, Fork()=%d\n", getpid(), getppid(),
0);
pid_t c7 = fork();
if (c7 == 0) {
// Process c7
printf("c7: PID=%d, PPID=%d, Fork()=%d\n", getpid(),
getppid(), 0);
_exit(0);
}
wait(NULL); // Wait for c7 to finish
exit(0);
}
c3 = fork();
if (c3 == 0) {
// Process c3
printf("c3: PID=%d, PPID=%d, Fork()=%d\n", getpid(), getppid(), 0);
exit(0);
}
return 0;
}