Skip to main content
Systems Architecture•Last Updated : 09 Oct 2026
~50 min read

Operating Systems & Concurrency

Core systems internals: virtual memory paging, translation lookaside buffers (TLB), process control blocks (PCB), thread synchronization, race conditions, and Coffman deadlock conditions.

Process Address Space vs Thread Shared Memory

A Process is an executing program instance with its own isolated virtual memory space (Text, Data, BSS, Heap, Stack) managed by the OS Process Control Block (PCB). A Thread is a lightweight unit of CPU execution within a process that shares the heap, data, and code segments, but possesses its own private Stack and Program Counter.

  • Context Switching Cost:Process context switch requires flushing the CPU Translation Lookaside Buffer (TLB) and switching page tables (CR3 register in x86). Thread context switch is ~10x cheaper because memory mappings remain identical.
  • Race Conditions:Occurs when multiple concurrent threads read and modify shared memory without synchronization, yielding non-deterministic bugs.
  • Mutex vs Counting Semaphore:A Mutex provides exclusive binary locking with ownership (only the locking thread can unlock). A Semaphore is a signaling mechanism with an integer counter (any thread can post/signal).
  1. Process Creation (fork + exec): fork() clones the parent process via Copy-On-Write (COW) page tables. execve() replaces the virtual address space with a new executable binary.
  2. Critical Section Protection via Mutex: Acquire lock (pthread_mutex_lock), perform atomic modification on shared state, and release lock (pthread_mutex_unlock).
  3. Deadlock & The 4 Coffman Conditions: A deadlock occurs if and only if all 4 conditions hold simultaneously: 1. Mutual Exclusion, 2. Hold and Wait, 3. No Preemption, 4. Circular Wait.
Definition: Copy-On-Write (COW)

An OS memory optimization where parent and child processes share the exact same physical memory pages marked as read-only after fork(), duplicating a page only when one process attempts a write.

Amdahl's Law for Parallel Speedup

Speedup(S) = 1 / ( (1 - P) + (P / N) )
Variable Definitions & Term Breakdown:
PProportion of program execution that can be parallelized (0.0 to 1.0)
NNumber of CPU cores / parallel processing threads
1 - PSerial portion of code that bottlenecks maximum possible speedup

Process vs Thread Comparison

AttributeProcessThread
Memory SpaceIsolated (Private Page Tables)Shared Heap, Data & Code; Private Stack
Creation OverheadHigh (Fork + Page Tables)
Low (~10-20KB stack)
Inter-CommunicationIPC (Pipes, Sockets, Shared Memory)
Direct Heap Memory Access
Crash Impact
Isolated (Parent survives)
Can crash entire process
Resource sharing, isolation, and communication mechanisms
Tip

To prevent Deadlocks in multi-threaded programs, ALWAYS acquire multiple mutex locks in a globally defined, consistent hierarchical order (e.g. always lock Resource A before Resource B).

PythonProducer-Consumer Queue with Semaphore & Mutex Simulation
1import threading
2import time
3import queue
4
5buffer = queue.Queue(maxsize=3)
6
7def producer():
8 for i in range(5):
9 item = f'Task-{i}'
10 buffer.put(item) # Blocks if buffer full
11 print(f'Produced: {item}')
12
13def consumer():
14 for _ in range(5):
15 item = buffer.get() # Blocks if buffer empty
16 print(f' Consumed: {item}')
17 buffer.task_done()
18
19t1 = threading.Thread(target=producer)
20t2 = threading.Thread(target=consumer)
21
22t1.start()
23t2.start()
24t1.join()
25t2.join()
26print('Producer-Consumer Completed Without Deadlock!')
Output
Produced: Task-0
Produced: Task-1
Produced: Task-2
  Consumed: Task-0
Produced: Task-3
  Consumed: Task-1
Produced: Task-4
  Consumed: Task-2
  Consumed: Task-3
  Consumed: Task-4
Producer-Consumer Completed Without Deadlock!
CC POSIX Thread (pthread) with Mutex Lock
1#include <stdio.h>
2#include <pthread.h>
3
4long counter = 0;
5pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
6
7void* worker(void* arg) {
8 for (int i = 0; i < 100000; i++) {
9 pthread_mutex_lock(&lock);
10 counter++; // Critical section
11 pthread_mutex_unlock(&lock);
12 }
13 return NULL;
14}
15
16int main() {
17 pthread_t t1, t2;
18 pthread_create(&t1, NULL, worker, NULL);
19 pthread_create(&t2, NULL, worker, NULL);
20 pthread_join(t1, NULL);
21 pthread_join(t2, NULL);
22 printf("Final Counter: %ld\n", counter);
23 return 0;
24}
Output
Final Counter: 200000

Quick Syntax & Reference Sheet

Concept / RuleSyntax / Usage
POSIX Thread Spawnpthread_create(&thread_id, NULL, worker_func, arg)
Mutex Lock / Unlockpthread_mutex_lock(&lock); /* critical section */ pthread_mutex_unlock(&lock);
Deadlock PreventionEliminate Circular Wait by enforcing global ascending lock acquisition order.

Common Pitfalls & Developer Mistakes

✕ Mistake 1:

Unlocking a Mutex from a different thread than the one that locked it

Why it happens: POSIX Mutexes enforce strict thread ownership. Unlocking from another thread results in undefined behavior.

Correction: Use Counting Semaphores or Condition Variables when signaling between different threads.
# Correct signaling pattern:
sem_post(&semaphore); // Thread A signals
sem_wait(&semaphore); // Thread B waits

Frequently Asked Questions

What is the difference between Concurrency and Parallelism?

Concurrency is about dealing with lots of things at once (structure, time-slicing on 1 core). Parallelism is about doing lots of things at once (executing simultaneously across multiple physical CPU cores).

Hands-On Practice Problems

Practice Coding Challenges (2)Solve in Cloud IDE
Article Tags:#Operating Systems#Concurrency#Processes#Threads#Mutexes#Virtual Memory
Was this lesson clear and helpful?

Discussion (0)

Sign in to ask questions and reply.
Loading discussion…
Discuss in community