fork: Creating new processes
• int fork(void)
• creates a new process (child process) that is identical to the
calling process (parent process)
• returns 0 to the child process
• returns child’s pid to the parent process
if (fork() == 0) {
printf("hello from childn");
} else {
printf("hello from parentn");
}
Fork is interesting (and often
confusing) because it is Called
Once but Returns Twice
Fork Example #1
void fork1()
{
int x = 1;
pid_t pid = fork();
if (pid == 0) {
printf("Child has x = %dn", ++x);
} else {
printf("Parent has x = %dn", --x);
}
printf("Bye from process %d with x = %dn", getpid(), x);
}
• Key Points
• Parent and child both run same code
• Distinguish parent from child by return value from fork
• Start with same state, but each has private copy
• Including shared output file descriptor
• Relative ordering of their print statements undefined
Fork Example #2
void fork2()
{
printf("L0n");
fork();
printf("L1n");
fork();
printf("Byen");
}
• Key Points
• Both parent and child can continue forking
L0 L1
L1
Bye
Bye
Bye
Bye
Fork Example #3
void fork3()
{
printf("L0n");
fork();
printf("L1n");
fork();
printf("L2n");
fork();
printf("Byen");
}
• Key Points
• Both parent and child can continue forking
L1 L2
L2
Bye
Bye
Bye
Bye
L1 L2
L2
Bye
Bye
Bye
Bye
L0
Fork Example #4
void fork4()
{
printf("L0n");
if (fork() != 0) {
printf("L1n");
if (fork() != 0) {
printf("L2n");
fork();
}
}
printf("Byen");
}
• Key Points
• Both parent and child can continue forking
L0 L1
Bye
L2
Bye
Bye
Bye
Fork Example #5
void fork5()
{
printf("L0n");
if (fork() == 0) {
printf("L1n");
if (fork() == 0) {
printf("L2n");
fork();
}
}
printf("Byen");
}
• Key Points
• Both parent and child can continue forking
L0 Bye
L1
Bye
Bye
Bye
L2
exit: Destroying Process
• void exit(int status)
• exits a process
• Normally return with status 0
• int atexit(void (*function)(void))
• atexit registers the given function to be called at normal
process termination
void cleanup(void) {
printf("cleaning upn");
}
void fork6() {
atexit(cleanup);
fork();
exit(0);
}
Zombies
• Idea
• When a process terminates, still consumes system
resources
• Various tables maintained by OS
• Called a “zombie” process
• Half alive and half dead
• Reaping
• Performed by parent on terminated child
• Parent is given exit status information
• Kernel discards process
• What if Parent Doesn’t Reap?
• If any parent terminates without reaping a child, then child
will be reaped by init process (parent of all processes)
linux> ./forks7 &
[1] 6639
Running Parent, PID = 6639
Terminating Child, PID = 6640
linux> ps
PID TTY TIME CMD
6585 ttyp9 00:00:00 tcsh
6639 ttyp9 00:00:03 forks
6640 ttyp9 00:00:00 forks <defunct>
6641 ttyp9 00:00:00 ps
linux> kill 6639
[1] Terminated
linux> ps
PID TTY TIME CMD
6585 ttyp9 00:00:00 tcsh
6642 ttyp9 00:00:00 ps
Zombie
Example
• ps shows child process as
“defunct” OR Zombie
• Killing parent allows child
to be reaped by init( )
void fork7()
{
if (fork() == 0) {
/* Child */
printf("Terminating Child, PID = %dn”, getpid());
exit(0);
} else {
printf("Running Parent, PID = %dn”, getpid());
while (1)
; /* Infinite loop */
}
}
linux> ./forks 8
Terminating Parent, PID = 6675
Running Child, PID = 6676
linux> ps
PID TTY TIME CMD
6585 ttyp9 00:00:00 tcsh
6676 ttyp9 00:00:06 forks
6677 ttyp9 00:00:00 ps
linux> kill 6676
linux> ps
PID TTY TIME CMD
6585 ttyp9 00:00:00 tcsh
6678 ttyp9 00:00:00 ps
Non-terminating Child Example
Child process still active even though
parent has terminated
Must kill explicitly, or else will keep
running indefinitely
void fork8()
{
if (fork() == 0) {
/* Child */
printf("Running Child, PID = %dn”, getpid());
while (1)
; /* Infinite loop */
} else {
printf("Terminating Parent, PID = %dn", getpid());
exit(0);
}
}
wait: Synchronizing with children
• int wait(int *child_status)
• suspends (blocks) current process until one of its children
terminates
• return value is the pid of the child process that terminated
• if child_status != NULL, then the object it points to will
be set to a status indicating why the child process terminated

forkwork.pptx

  • 1.
    fork: Creating newprocesses • int fork(void) • creates a new process (child process) that is identical to the calling process (parent process) • returns 0 to the child process • returns child’s pid to the parent process if (fork() == 0) { printf("hello from childn"); } else { printf("hello from parentn"); } Fork is interesting (and often confusing) because it is Called Once but Returns Twice
  • 2.
    Fork Example #1 voidfork1() { int x = 1; pid_t pid = fork(); if (pid == 0) { printf("Child has x = %dn", ++x); } else { printf("Parent has x = %dn", --x); } printf("Bye from process %d with x = %dn", getpid(), x); } • Key Points • Parent and child both run same code • Distinguish parent from child by return value from fork • Start with same state, but each has private copy • Including shared output file descriptor • Relative ordering of their print statements undefined
  • 3.
    Fork Example #2 voidfork2() { printf("L0n"); fork(); printf("L1n"); fork(); printf("Byen"); } • Key Points • Both parent and child can continue forking L0 L1 L1 Bye Bye Bye Bye
  • 4.
    Fork Example #3 voidfork3() { printf("L0n"); fork(); printf("L1n"); fork(); printf("L2n"); fork(); printf("Byen"); } • Key Points • Both parent and child can continue forking L1 L2 L2 Bye Bye Bye Bye L1 L2 L2 Bye Bye Bye Bye L0
  • 5.
    Fork Example #4 voidfork4() { printf("L0n"); if (fork() != 0) { printf("L1n"); if (fork() != 0) { printf("L2n"); fork(); } } printf("Byen"); } • Key Points • Both parent and child can continue forking L0 L1 Bye L2 Bye Bye Bye
  • 6.
    Fork Example #5 voidfork5() { printf("L0n"); if (fork() == 0) { printf("L1n"); if (fork() == 0) { printf("L2n"); fork(); } } printf("Byen"); } • Key Points • Both parent and child can continue forking L0 Bye L1 Bye Bye Bye L2
  • 7.
    exit: Destroying Process •void exit(int status) • exits a process • Normally return with status 0 • int atexit(void (*function)(void)) • atexit registers the given function to be called at normal process termination void cleanup(void) { printf("cleaning upn"); } void fork6() { atexit(cleanup); fork(); exit(0); }
  • 8.
    Zombies • Idea • Whena process terminates, still consumes system resources • Various tables maintained by OS • Called a “zombie” process • Half alive and half dead • Reaping • Performed by parent on terminated child • Parent is given exit status information • Kernel discards process • What if Parent Doesn’t Reap? • If any parent terminates without reaping a child, then child will be reaped by init process (parent of all processes)
  • 9.
    linux> ./forks7 & [1]6639 Running Parent, PID = 6639 Terminating Child, PID = 6640 linux> ps PID TTY TIME CMD 6585 ttyp9 00:00:00 tcsh 6639 ttyp9 00:00:03 forks 6640 ttyp9 00:00:00 forks <defunct> 6641 ttyp9 00:00:00 ps linux> kill 6639 [1] Terminated linux> ps PID TTY TIME CMD 6585 ttyp9 00:00:00 tcsh 6642 ttyp9 00:00:00 ps Zombie Example • ps shows child process as “defunct” OR Zombie • Killing parent allows child to be reaped by init( ) void fork7() { if (fork() == 0) { /* Child */ printf("Terminating Child, PID = %dn”, getpid()); exit(0); } else { printf("Running Parent, PID = %dn”, getpid()); while (1) ; /* Infinite loop */ } }
  • 10.
    linux> ./forks 8 TerminatingParent, PID = 6675 Running Child, PID = 6676 linux> ps PID TTY TIME CMD 6585 ttyp9 00:00:00 tcsh 6676 ttyp9 00:00:06 forks 6677 ttyp9 00:00:00 ps linux> kill 6676 linux> ps PID TTY TIME CMD 6585 ttyp9 00:00:00 tcsh 6678 ttyp9 00:00:00 ps Non-terminating Child Example Child process still active even though parent has terminated Must kill explicitly, or else will keep running indefinitely void fork8() { if (fork() == 0) { /* Child */ printf("Running Child, PID = %dn”, getpid()); while (1) ; /* Infinite loop */ } else { printf("Terminating Parent, PID = %dn", getpid()); exit(0); } }
  • 11.
    wait: Synchronizing withchildren • int wait(int *child_status) • suspends (blocks) current process until one of its children terminates • return value is the pid of the child process that terminated • if child_status != NULL, then the object it points to will be set to a status indicating why the child process terminated

Editor's Notes

  • #2 System call fork() is used to create processes. It takes no arguments and returns a process ID. The purpose of fork() is to create a new process, which becomes the child process of the caller. After a new child process is created, both processes will execute the next instruction following the fork() system call.
  • #3 Sample Output: Parent has x = 0 Bye from process 1407 with x = 0 Child has x = 2 Bye from process 1409 with x = 2
  • #4 Sample output: L0 L1 Bye L1 Bye Bye Bye
  • #5 Sample Output L0 L1 L2 L1 Bye L2 L2 Bye Bye L2 Bye Bye Bye Bye Bye
  • #6 Sample Output: L0 L1 L2 Bye Bye Bye Bye
  • #7 Sample Output: L0 Bye L1 Bye L2 Bye Bye
  • #9 init is the parent of all processes on the system, it is executed by the kernel and is responsible for starting all other processes; it is the parent of all processes whose natural parents have died and it is responsible for reaping those when they die.
  • #10 Processes marked <defunct> are dead processes (so-called "zombies") that remain because their parent has not destroyed them properly. These processes will be destroyed by init(8) if the parent process exits.