Processes and Threads

The process abstraction, process states, the PCB, context switches, fork(), and threads.

A program is a passive file on disk. A process is a program in execution: its code plus everything needed to run it, such as the current instruction, register values, memory and open files. Running the same program twice creates two separate processes.

Process address spaceTextthe program's machine codeDataglobal and static variablesHeapmalloc / new; grows upwardsStackfunction calls and local variables; grows downwards
The memory layout of a process (addresses grow downwards in this picture)

Process states

NewReadyRunningWaitingDone
Process state transitions
TransitionWhen it happens
New → Readythe process has been created and loaded
Ready → Runningthe scheduler picks it (dispatch)
Running → Readyits time slice ends (timer interrupt) or a higher-priority process arrives
Running → Waitingit waits for I/O or an event
Waiting → Readythe I/O or event completes
Running → Done (terminated)it finishes or is killed

Note that a waiting process never goes straight to Running: it first becomes Ready.

The process control block

The OS keeps one process control block (PCB) per process, holding: the process ID, state, program counter, saved CPU registers, scheduling information (priority), memory-management information (page table pointer), open files and accounting data.

A context switch saves the running process's state into its PCB and loads the next process's state from its PCB. It is pure overhead: no useful work is done while switching.

Creating processes with fork()

In Unix, fork() creates a child process that is an almost exact copy of the parent. It returns 0 in the child and the child's process ID (a positive number) in the parent. wait() lets the parent wait for a child to finish.

#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void) {
    pid_t pid = fork();
    if (pid == 0) {
        printf("child: fork returned 0\n");
        return 0;
    }
    wait(NULL);                     /* parent waits, so the child prints first */
    printf("parent: fork returned a positive pid? %s\n", pid > 0 ? "yes" : "no");
    return 0;
}
Output
child: fork returned 0
parent: fork returned a positive pid? yes

Every call to fork() doubles the number of processes running the code after it. So n fork() calls in a row create 2ⁿ processes in total, that is 2ⁿ − 1 children.

#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void) {
    fork();
    fork();
    fork();
    printf("hello\n");
    fflush(stdout);
    while (wait(NULL) > 0) { }      /* wait for any children */
    return 0;
}
Output
hello
hello
hello
hello
hello
hello
hello
hello

Threads

A thread is a unit of execution inside a process. Threads of the same process share its code, data, heap and open files, but each thread has its own program counter, registers and stack.

ProcessThread
Memoryseparate address spaceshared with other threads of the process
Creation and switching costhighlow
Communicationneeds IPC (pipes, sockets, shared memory)through shared variables
A crash affectsonly that processthe whole process
  • User-level threads are managed by a library without kernel support: fast to switch, but if one thread makes a blocking system call, the whole process blocks.
  • Kernel-level threads are known to the kernel: a blocked thread does not block the others, and threads can run on several CPUs at once.

GATE-style practice questions

GATE-styleNAT · numerical answer

A program executes fork() 5 times in a row (not inside any condition). How many child processes are created?

Show answer and explanationAnswer: 31

After n fork() calls there are 2ⁿ processes in total. One of them is the original parent, so 2⁵ − 1 = 31 are children.

GATE-styleNAT · numerical answer

Consider the following code. How many times is X printed?

for (int i = 0; i < 3; i++) { fork(); printf("X\n"); } (stdout is flushed after every printf)

Show answer and explanationAnswer: 14

In iteration i (0, 1, 2) the fork doubles the number of processes to 2^(i+1), and each of them prints once. Total prints: 2 + 4 + 8 = 14.

GATE-styleMSQ · one or more correct answers

Which items are shared by all threads of the same process? (Select all that apply.)

Show answer and explanationAnswer: A, B, D

Threads share the whole address space (code, globals, heap) and the open files. Each thread has its own stack, registers and program counter, so that it can run its own sequence of function calls.

GATE-styleMCQ · one correct answer

Which state transition is not possible in the standard five-state process model?

Show answer and explanationAnswer: C

When the event a process is waiting for occurs, the process becomes Ready and must be dispatched by the scheduler again before it runs.