What Is a Process?
A program is a static file stored on disk, consisting of executable instructions and data. In contrast, a process represents the dynamic execution of that program, encompassing its creation, scheduling, and eventual termination.
Essential Process Management Commands
top: Displays real-time system processes sorted by CPU usage.- PID: Unique process identifier (always > 0).
- Nice value: Ranges from -20 (highest priority) to 19 (lowest) in Linux.
- Process states:
R: Running or runnableS: Interruptible sleepD: Uninterruptible sleepT: StoppedZ: ZombieX: Dead (rarely visible)
nice: Launches a process with a specific nice value.
Example:nice -n 10 ./my_apprenice: Adjusts the priority of a running process.
Example:renice -n 5 1234kill/killall: Terminate processes by PID or name.
Examples:kill -9 1234,killall -9 my_appps -ef: Lists all processes with full details (including PPID and PID).
Filter example:ps -ef | grep app_namepstree: Visualizes parent-child process relationships as a tree.ps aux: Alternative detailed process listing../app &: Runs a program in the background.jobs: Shows background jobs in the current shell.fg %1: Brings job #1 to the foreground.
Process Memory Layout (32-bit Systems)
Each process operates within a 4GB virtual address space divided into segments:
- Text segment: Contains executable code (read-only).
- Data segment:
- Initialized global/static variables
- Uninitialized global/static variables (.bss)
- String literals
- System data segment:
- Heap: Dynamically allocated memory (grows upward)
- Stack: Function call frames and local variables (grows downward)
The Memory Management Unit (MMU) maps this virtual space to physical RAM, ensuring proces isolation.
Process Scheduling
Linux uses several scheduling strategies:
- First-Come-First-Served (FCFS)
- Priority-based scheduling
- Round-robin with time slices
- Multilevel feedback queues
- Load balancing across CPUs
Although systems appear to run multiple processes simultaneously (macroscopic parallelism), the CPU executes them one at a time in rapid succession (microscopic serialism).
Key Process System Calls
Process Creation: fork()
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
Returns 0 in the child process, the child's PID in the parent, or -1 on error.
Process Identification
getpid(): Returns current process IDgetppid(): Returns parent process ID
Process Termination
exit(int status): Performs cleanup (flushes buffers) before termination_exit(int status): Terminates immediately without cleanup
Process Lifecycle Issues
Zombie processes occur when a child exits but the parent hasn't collected its exit status. Solutions:
- Terminate the parent first (child becomes orphaned)
- Use
wait()to reap child processes
Orphan processes (parent dies first) are adopted by init (PID 1), which automatically reaps them.
Reaping Child Processes: wait()
#include <sys/wait.h>
pid_t wait(int *status);
Blocks until a child terminates. Use macros to interpret status:
WIFEXITED(status): True if child exited normallyWEXITSTATUS(status): Exit code (if normally exited)WIFSIGNALED(status): True if killed by signalWTERMSIG(status): Signal number (if killed)
Replacing Process Image: exec Family
These functions replace the current process image with a new program:
execl(),execlp(): Arguments as listexecv(),execvp(): Arguments as arrayexecle(),execvpe(): Custom environment
Suffix meanings:
l= list argumentsv= vector (array) argumentse= explicit environmentp= search PATH for executable
Environment Variable Management
char *getenv(const char *name);
int setenv(const char *name, const char *value, int overwrite);
Example usage:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
char cwd[1024];
getcwd(cwd, sizeof(cwd));
setenv("PATH", cwd, 1);
execlp("hello", "hello", "arg1", "arg2", NULL);
perror("execlp failed");
return 1;
}
Practical Exercise: Creating Multiple Children
Create 9 child processes that print their PIDs, then have the parent print all child PIDs:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
pid_t children[9];
for (int i = 0; i < 9; i++) {
children[i] = fork();
if (children[i] == 0) {
printf("Child %d: PID=%d, Parent PID=%d\n",
i, getpid(), getppid());
_exit(0);
}
wait(NULL); // Reap immediately to prevent zombies
}
printf("Parent PID: %d\n", getpid());
for (int i = 0; i < 9; i++) {
printf("Child %d PID: %d%s", i, children[i],
(i == 4) ? "\n" : " ");
}
printf("\n");
return 0;
}