| Lesson 3 | Forking |
| Objective | Describe the mechanism by which processes come into being. |
fork() system call creates a new process called a child process, duplicating the calling (parent) process.fork() call.pid_t pid = fork();
if (pid < 0) {
// Fork failed
} else if (pid == 0) {
// Child process executes here
} else {
// Parent process executes here, pid contains child's PID
}
0.exec() family system calls (execl, execvp, execve, etc.).exec() completely replaces the child’s process image (code, data, stack) with a new program loaded from disk into memory.if (pid == 0) {
execl("/bin/ls", "ls", "-l", NULL);
// If exec() returns, an error has occurred
}
fork() – Create a new, identical copy of the calling process.exec() – Load and execute a new executable into this newly created process.fork) and program execution (exec).init or systemd with PID 1) is created by a parent.
init/systemd) creates system processes.bash, zsh) spawn user-level applications as their children.wait() call) for the child process to terminate.Parent Process
│
│ fork()
▼
Child Process (exact copy)
│
│ exec()
▼
Child executes a new program
---
Key System Calls Recap:
| Call | Functionality |
|---|---|
fork() |
Creates a duplicate of the calling process (child). |
exec() |
Replaces the current process image with a new executable. |
wait() |
Parent waits for child process completion. |
_exit() |
Process termination call to end a process cleanly. |
grep yes *.cto his or her login shell. At this point, the shell needs to start a new grep process, wait for it to finish, then generate a new output prompt and wait for the next command. The mechanism by which this occurs is called forking.
fork().
This system call asks the operating system to clone whatever process calls it. fork() call, the system replaces the shell process with two new processes. These processes are
identical in every respect, except that one is labeled "parent" and the other is labeled "child." The parent process, which is identical to the original shell, then begins to wait for the child process to terminate. exec(). While
fork() clones a process, exec() starts a new process that replaces whatever process called it. In this instance, the child shell exec is the new grep process, and the child shell disappears, replaced by grep. fork(), every process has a parent process, the process that called the fork() that created it. Because all
processes derive ultimately from init with PID 1, tracing the chain of ancestry back from any running process must ultimately lead to
init.
kill command. kill 34
pkill (Safest and Recommended)
Syntax:
pkill -signal -u username -f "process_pattern"
Example (terminate gracefully):
pkill -TERM -u oracle -f "sqlplus"
Example (forceful kill, after graceful attempt fails):
pkill -KILL -u oracle -f "sqlplus"
-TERM (default) politely requests termination, allowing processes to perform cleanup.-KILL immediately terminates processes; use only when -TERM fails.killall (Second safest)
killall works similarly to pkill but requires exact process names:
Example (graceful):
killall -TERM firefox
Example (forceful):
killall -KILL firefox
You can carefully pick processes and kill them explicitly:
ps aux | grep [p]rocess_name kill -TERM pid1 pid2 pid3
Example:
kill -TERM 1234 5678 9012
To forcefully kill (only if gentle attempts fail):
kill -KILL 1234 5678 9012
xargs and ps (safe if used carefully)
To kill processes matching a pattern:
ps aux | grep '[p]rocess_pattern' | awk '{print $2}' | xargs -r kill -TERM
Example:
ps aux | grep '[j]ava -jar app.jar' | awk '{print $2}' | xargs -r kill -TERM
SIGTERM) first, giving the process a chance to clean up.SIGKILL) only when necessary.ps, pgrep, or pidof.-u username) reduces risk.pgrep -a) before execution.