Process creation: fork
Fork() causes creation of new process. A new process (Child process) is an exact copy of the calling process, memory values and open resources except:
- The child process has a unique process ID
- The child process resource utilizations are set to 0
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void)
The vfork function creates the new process, just like fork, without copying the address space of the parent into the child, as the child won’t reference that address space; the child simply calls exec (or exit) right after the vfork. Instead, the child runs in the address space of the parent until it calls either exec or exit. The vfork also executes the child process first and resumes the parent process when the child terminates.
Example using vfork()
int globvar = 6; int main(void) int var; /* automatic variable on the stack */ pid_t pid; var = 88; printf("before vfork\n"); /* we don’t flush stdio */ if ((pid = vfork()) < 0) { err_sys("vfork error"); } else if (pid == 0) { /* child */ globvar++; /* modify parent’s variables */ var++; _exit(0); /* child terminates */ } /* parent continues here */ printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var); exit(0); }Running this program give us:
$ ./a.out before vfork pid = 29039, glob = 7, var = 89
Wait
A parent might want to wait for a child to complete.
A parent might want to know the exit code of a child.
System call to wait for a child:
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *stat_loc)
A parent might want to know the exit code of a child.
System call to wait for a child:
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *stat_loc)
wait() requires you include the sys/types.h and sys/wait.h header files.
wait() suspends execution of the calling process until one of its children terminates.
After calling wait() a process will:
After calling wait() a process will:
- block if all of children process are still running.
- return immediately with the PID of a terminated child, if there is a terminated child
- return immediately with an error(-1) if it doesn't have any child processes.
- Return the pid of the terminated child or -1 on error
- Status encodes the exit status of the child and how a child exited (normally or killed by signal)
- There are macros to process exit status:
WIFEXITED | tell you if child terminated normally |
WEXITSTATUS | gives you the exit status |
WIFSIGNALED | Nonzero if child is terminated on an caught signal |
WTERMSIG | if WIFSIGNALED is nonzero, this return a signal number |
WIFSTOPPED | Nonzero if the child ha stopped |
WSTOPSIG | if WIFSTOPPED is nonzero, this return a signal number |
Example wait1.c, download code here
int main() pid_t pid; char *message; int n; printf("fork program starting\n"); pid = fork(); switch(pid) case -1: perror("fork failed"); exit(1); case 0: message = "This is the child"; n = 5; break; default: message = "This is the parent"; n = 3; break; } for(; n > 0; n--) { puts(message); sleep(1); } if (pid != 0) { int stat_val; pid_t child_pid; child_pid = wait(&stat_val); } }Running wait1.c
$ ./wait1 fork program starting This is the child This is the parent This is the parent This is the child This is the parent This is the child This is the child This is the childExample wait2.c, download code here
int main() pid_t pid; char *message; int n; printf("fork program starting\n"); pid = fork(); switch(pid) case -1: perror("fork failed"); exit(1); case 0: message = "This is the child"; n = 5; break; default: wait(NULL); message = "This is the parent"; n = 3; break; } for(; n > 0; n--) { puts(message); sleep(1); } }
Running wait2.c
$ ./wait2 fork program starting This is the child This is the child This is the child This is the child This is the child This is the parent This is the parent This is the parent
Exec()
- The exec system call replaces the program being run bt a process by a different one
- The new program starts executing from the beginning.
- On success, exec never return, on failure exec return -1.
- Exec() is not a specific function, but a family of function
- First parameter: name of executable ; then commandline parameter for executable ; these are passed as argv[0], argv[1], …, to the main program of the executable.
- execl and execv differ from each other only in how the arguments for the new program of the are passed.
- execlpand execvpdiffer from execland execvonly in that you don’t have to specify full path to new program
int main (void) { printf ("Before exec\n"); execl ("/bin/ls", "ls", "-l", (char *)NULL); perror ("execl"); exit (1); }
Example using execv:
int main (void) { printf ("Before exec\n"); char *argv[] = {"ls", "-l", NULL); execv ("/bin/ls", args); perror ("execv"); exit (1); }
Example using execvp
int main (void) { printf ("Before exec\n"); char *argv[] = {"ls", "-l", NULL); execv (args[0], args); perror ("execv"); exit (1); }
Zombie and orphan process
- Using fork to create processes can be very useful, but you must keep track of child processes. When a child process terminates, an association with its parent survives until the parent in turn either terminates normally or calls wait.
- The child process entry in the process table is therefore not freed up immediately. Although no longer active, the child process is still in the system because its exit code needs to be stored in case the parent subsequently calls wait. It becomes what is known as defunct, or a zombie process. Need to avoid zombie process, because they consume resources until parent clean them up.
- If the parent process terminates before the child. The child process automatically gets the process with PID 1768 (init--user) as parent.
- There’s another system call that you can use to wait for child processes. It’s called waitpid, and you can use it to wait for a specific process to terminate.
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t, int *stat_loc, int options);
pid_t waitpid(pid_t, int *stat_loc, int options);
- The pid argument specifies the PID of a particular child process to wait for.
- it will write status information to the location pointed to by stat_loc
- The options argument allows you to modify the behavior of waitpid. The most useful option is WNOHANG, which prevents the call to waitpid from suspending execution of the caller.
References
[2] W.Richard Stevens, Stephen A.Rogo [Advanced programming in the UNIX Environment]
[3] Beginning Linux Programming 4th Edition
[3] Beginning Linux Programming 4th Edition
If you want parent to wait for all child process to finish you can follows code below:
ReplyDeletewhile(wait(NULL) != -1){;}