Code of the Day
AdvancedConcurrency with pthreads

Threads vs. processes

Understand the difference between processes and threads in C — memory isolation, the cost of context switching, and when to use each.

CAdvanced10 min read
By the end of this lesson you will be able to:
  • Explain what a process is and what resources it owns
  • Explain what a thread is and how threads share a process's address space
  • Describe the trade-offs between thread-level and process-level concurrency
  • Identify the main risks of shared memory between threads

Modern computers have multiple cores. To use them, programs need to do more than one thing at a time. In C, you choose between processes (isolated programs) and threads (concurrent execution paths within a single program). Understanding the difference determines how you design concurrent systems.

What is a process?

A process is an instance of a running program with its own:

  • Virtual address space (the process cannot read another process's memory).
  • Open file descriptors.
  • Signal handlers.
  • User and group IDs.
  • Environment variables.

Creating a new process with fork() copies the parent's address space (using copy-on-write). Processes communicate through pipes, sockets, shared memory (explicitly requested), or files. The OS kernel isolates them — a crash in one process does not corrupt another.

What is a thread?

A thread is a concurrent execution path within a single process. All threads in a process share:

  • The same virtual address space (all globals, heap, and open files).
  • The same file descriptors.
  • Signal handlers (though signal masks can differ).

Each thread has its own:

  • Stack.
  • CPU registers and program counter.
  • Thread-local storage (declared with _Thread_local or __thread).

Creating a thread vs. a process

AspectProcess (fork)Thread (pthread_create)
MemoryIsolated copyShared address space
Creation costHigh (copy page tables)Low
CommunicationIPC: pipes, sockets, shmShared variables (with synchronisation)
Crash isolationYesNo — one thread can corrupt all
ParallelismYes (multi-process)Yes (multi-thread, same process)

For CPU-bound work across multiple cores, threads are the natural fit. For isolation, security boundaries, or running separate programs, processes are appropriate.

The data race problem

When multiple threads access shared memory and at least one is writing, without synchronisation, you have a — the result is undefined behaviour:

int counter = 0; /* shared between two threads */

void *increment(void *arg) {
    for (int i = 0; i < 1000000; i++) {
        counter++; /* NOT ATOMIC: read-modify-write is three operations */
    }
    return NULL;
}

counter++ compiles to (approximately): load counter into a register, add 1, store back. If two threads execute this simultaneously, one thread's update can be lost:

Thread 1: load counter (value: 5)
Thread 2: load counter (value: 5)
Thread 1: add 1 → 6, store → counter = 6
Thread 2: add 1 → 6, store → counter = 6  ← Thread 1's update lost

After a million increments from each of two threads, counter should be 2,000,000 but might be anything less.

POSIX threads (pthreads)

On Linux and macOS, the POSIX thread library (pthreads) provides the standard threading API. The functions are in <pthread.h> and the library is linked with -lpthread:

gcc -Wall -pthread program.c -o program

(Use -pthread rather than -lpthread — it also sets the right preprocessor macros.)

The core functions are:

  • pthread_create — create a thread.
  • pthread_join — wait for a thread to finish.
  • pthread_mutex_lock / pthread_mutex_unlock — synchronise access to shared data.
  • pthread_cond_wait / pthread_cond_signal — coordinate between threads.

These are covered in the following lessons.

C11 added <threads.h>. The C11 standard includes a thread API (thrd_create, mtx_lock, etc.) that abstracts over platform differences. In practice, POSIX threads are more widely supported and have more documentation. The concepts are the same; the function names differ.

Where to go next

Next: creating threads with pthread_create — the full API for starting, identifying, and joining threads.

Finished reading? Mark it complete to track your progress.

On this page