109 / 163 · C11 · 8 min
Interlude: Process API
This interlude presents the core UNIX interfaces for process creation and control. fork duplicates the calling process so parent and child resume from the same return point with different values, wait lets a parent block until a child finishes, and the exec family replaces the entire process image with a new executable. Together they form a compact yet highly expressive API.
In this lesson
How fork() Duplicates a Running Process
fork instantly clones the caller: the child receives its own address space, registers and instruction pointer, yet resumes immediately after the fork return as if it had issued the call itself. The parent is given the child's PID while the child is given zero, allowing an immediate split in control flow. Thereafter the two processes are independent; the scheduler decides who runs next, so unsynchronized output order is unpredictable.
Using wait() to Synchronize Parent and Child
A parent that calls wait or waitpid suspends until one of its children exits and its termination status is reaped. This both eliminates zombies and makes the order of later statements deterministic: whichever process is scheduled first, the parent will not continue until the child has finished printing and terminated.
exec() Completely Overwrites the Current Image
A child frequently calls one of the exec-family functions right after fork. On success the entire address space (code, data and stack) is replaced by the named executable, so statements after the exec never execute. Shells rely on exactly this fork-then-exec sequence to launch the commands a user types.
Pitfalls
- Continuing without inspecting the fork return value can send both parent and child down the wrong path
- Omitting wait turns an already-exited child into a zombie that occupies a process-table slot
- Assuming the child always prints first when no wait is present
Run an example
Minimum C11 · complete program · Download .c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void) {
pid_t rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
return 1;
} else if (rc == 0) {
printf("hello from child\n");
} else {
wait(NULL);
printf("hello from parent after wait\n");
}
return 0;
}
Compile locally
gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-05-process-api.c -o example && ./exampleExpected result
hello from child
hello from parent after wait
CHECK YOUR UNDERSTANDING
Close the answer. Explain it.
Once the parent contains wait(NULL), why does the child's output always appear before the parent's output?
Show a reference answer
Whichever process the scheduler picks first, the parent blocks inside wait until the child has exited. The child prints and then terminates, so its line necessarily appears first.
Check the sources
Drafts and official chapters change. The version mark is only the example’s minimum.