JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

Program vs Process: Bringing Code to Life

A program is a recipe sitting on a shelf; a process is that recipe being cooked in a real kitchen. Meet the single most important idea in operating systems — and why a program and a process are emphatically not the same thing.

A recipe on the shelf, a recipe being cooked

In the earlier rungs you met the operating system and the great divide between user programs and the kernel. Now we reach the idea that the whole subject is built on. Picture a cookbook sitting on a shelf. It is just paper and ink — complete, but inert. Nothing is happening. The moment a cook carries it into a kitchen, gathers ingredients, and starts chopping, something new exists: a recipe in mid-cooking, with half-diced onions, a pot already simmering, and a finger marking the current step.

That distinction is exactly the difference between a program and a process. A program is a passive file on disk — the compiled instructions, sitting there whether or not anyone runs it. A process is a program in execution: alive, in motion, carrying all the in-progress state that running actually requires. The cookbook is the program; the cooking is the process. This is the heart of the program-versus-process distinction, and getting it straight unlocks everything that follows.

Where a process lives: its address space

When the OS brings a program to life, it carves out a private region of memory for it called the address space — the process's own kitchen, walled off from everyone else's. Each process believes it has the whole machine to itself. Inside that space, memory is laid out into a few clear neighbourhoods, and you'll explore them in detail in the next guide. For now, a quick tour: the text segment holds the actual machine instructions (the printed recipe steps); the data segment holds variables that exist for the whole run (the pantry of staples).

Two regions grow and shrink as the program runs. The heap is the open counter space where the cook reaches for more room whenever a dish needs it — memory you request on the fly. The stack is the neat pile of recipe cards, one per task-in-progress: each time the program calls a function, a fresh card goes on top, and when the function returns, that card is thrown away. The heap typically grows upward toward higher addresses and the stack grows downward toward lower ones, leaving a large gap between them so both have room to expand.

So a simple mental map of the address space, from low addresses up, runs: text (the code) at the bottom, then data (and a region called bss for variables that start at zero) above it, then the heap growing upward, a wide gap, and finally the stack growing downward from the top. That gap in the middle is deliberate: it gives the two growing regions room to expand without colliding for as long as possible.

The kernel's clipboard: the process control block

Memory is only half the story. To keep a process alive and to pause and resume it later, the kernel must remember a great deal of bookkeeping about it. It stores all of that in a process control block, or PCB — one per process, like a clipboard the kitchen manager keeps for every cook on shift. Each clipboard records who the cook is and exactly where they paused if the manager pulled them off the line.

What goes on the clipboard? A unique process ID (the PID, the cook's name tag); the current state (cooking, waiting for an ingredient, or ready to resume); the saved CPU registers, above all the program counter that marks the exact instruction to run next; pointers to that process's address space; and a list of open files and other resources. The kernel keeps every PCB in a master list — the process table — so it can always find any process at a glance.

A process is never just running

Here is a surprise for beginners: at any instant, most processes are not actually executing. A single CPU core can run only one instruction stream at a time, yet your machine juggles hundreds of processes. The kernel pulls this off by moving each process through a small set of states. The three that matter most are ready (able to run, just waiting for a turn on the CPU), running (actually on the CPU right now), and waiting or blocked (stuck until something happens, like a key being pressed or a disk read finishing).

Processes shuttle between these states constantly. A ready process gets picked by the scheduler and becomes running; a running process that asks the disk for data drops to waiting and gives up the CPU so someone else can use it; when the disk replies, the process returns to ready (not straight to running — it still has to wait its turn). All the ready processes sit in a line called the ready queue, and choosing who runs next is the job of CPU scheduling, a whole topic you'll dive into in a later rung.

         admitted          dispatch
  [new] --------> [ready] -----------> [running] ---> [done]
                    ^   ^                 |  |
         I/O done   |   | quantum expires |  | exit
      (event ready) |   +-----------------+  |
                     \                        |
                      \---- [waiting] <------/
                              I/O or event wait
The classic process state diagram. Note that a process leaving 'waiting' returns to 'ready', not directly to 'running' — it must still be dispatched.

Swapping cooks: the context switch

When the kernel takes the CPU away from one process and hands it to another, it performs a context switch. Think of the kitchen manager pulling Cook A off the stove so Cook B can take over the same burner. The manager must first write down exactly where Cook A paused — every register, the program counter — onto Cook A's clipboard, and then read Cook B's clipboard to restore Cook B to precisely where they left off. Done right, neither cook ever notices they were interrupted.

  1. Something triggers the switch — a timer interrupt fires, or the running process blocks on I/O.
  2. The kernel saves the running process's state (registers, program counter) into its PCB.
  3. The scheduler chooses the next process to run from the ready queue.
  4. The kernel loads that process's saved state from its PCB back into the CPU registers.
  5. Execution resumes from the new process's program counter — as if it had never stopped.

Born, related, and laid to rest

Where do processes come from? On Unix-like systems, the surprising answer is that a process is born by cloning. An existing process calls fork, which makes a near-identical copy of itself — same code, same data, even the same place in the program. The original is the parent and the copy is the child, and this parent-child relationship links every process to the one that created it. The child usually then calls exec to replace its copied program with a different one — like a cook who clones themselves and then hands the twin a brand-new recipe to cook instead.

Because every process has a parent, all processes form a single family tree — the process tree. At its root sits one special process with PID 1, the init process, started by the kernel at boot; every other process descends from it. When a process finishes, it calls exit to bow out, and its parent calls wait to collect the exit status and let the kernel free the leftovers. If a parent never reaps a finished child, that child lingers as a zombie (done cooking but still on the books); if a parent dies first, its running children become orphans and get adopted by init. You'll trace all of this in detail in the last two guides of this rung.

Finally, walled-off processes still need to talk. Because each lives in its own private address space, one process cannot simply read another's variables. The kernel offers controlled channels — pipes, message queues, shared memory, and more — collectively called inter-process communication. It's like cooks at separate stations passing notes and trays through a hatch rather than barging into each other's kitchens. That's our first glimpse; the full menu comes later in this rung.