OSOperating Systems · Lesson 2 of 7

Processes

A process is a running program plus everything it owns: its memory, its open files, its identity. It's also the OS's unit of protection — each process lives in its own bubble.

A program is a file on disk; a process is that program running. Each process gets its own virtual address space (it thinks it has all of memory to itself), its own file descriptor table, an ID (PID), an owner, and a parent. Chrome with 40 tabs is dozens of processes on purpose — one tab crashing can't corrupt another.

Bash
ps aux | head            # snapshot of all processes
# USER  PID  %CPU %MEM  ... COMMAND
# noah  4312 12.0  2.3  ... firefox

pstree | head            # processes form a family tree
echo $$                  # PID of your shell
kill 4312                # ask process 4312 to exit (SIGTERM)
kill -9 4312             # force it, no cleanup (SIGKILL)

# A process's memory layout, roughly:
#  [ code | globals | heap ->     ...      <- stack ]
#  heap grows up (malloc/new), stack grows down (calls)
Python
# Creating processes — the Unix way is fork + exec:
import os, subprocess

# High level (what you'll actually use):
result = subprocess.run(["ls", "-l"], capture_output=True, text=True)
print(result.stdout)

# What's underneath: fork() clones the current process;
# exec() replaces the clone's program with a new one.
pid = os.fork()
if pid == 0:
    os.execvp("echo", ["echo", "I am the child"])
else:
    os.waitpid(pid, 0)     # parent waits for child to finish
    print("child done")
◆ Note
Signals are the OS's way to poke a process: Ctrl+C sends SIGINT, kill sends SIGTERM (please exit — handlers can run cleanup), kill -9 sends SIGKILL (unblockable, immediate). A 'zombie' is a dead child whose parent hasn't collected its exit status yet — harmless in small numbers, a bug in large ones.