AiTechWorlds
AiTechWorlds
A restaurant has one chef who must prepare every course of a five-course meal alone. She boils the pasta, waits, plates it, then starts the soup, waits, then works on the dessert. The oven sits idle while she chops vegetables. The grill goes cold while she stirs sauce. The meal takes two hours.
Now add a second chef. Both work in the same kitchen, sharing the same refrigerator, the same pantry, the same oven. One handles hot dishes, the other handles cold prep. They communicate constantly. The meal is done in forty-five minutes.
Threads are those two chefs. They share the same process resources — the same memory space, the same open files, the same code — but run independently on separate CPU cores (or take turns on the same core). This is concurrency, and it is one of the most powerful ideas in systems programming.
Single-threaded programs are simple but limited. Consider a web browser:
All of these would be impossible with a single thread. The UI would freeze every time a network request was made. Threads are the solution.
Reasons to use threads:
| Feature | Process | Thread |
|---|---|---|
| Address space | Own private address space | Shares process address space |
| Code segment | Private | Shared with all process threads |
| Data / Heap | Private | Shared with all process threads |
| Stack | Own stack | Own private stack |
| Registers / PC | Own (saved in PCB) | Own (saved in Thread Control Block) |
| Open files | Private | Shared |
| Creation cost | High (full memory copy via fork) | Low (just a new stack + TCB) |
| Context switch | Expensive (TLB flush, page table swap) | Cheap (same address space) |
| Crash isolation | Process crash doesn't affect others | Thread crash kills entire process |
Each thread has its own private elements and shares the rest of the process with its siblings.
Process Memory Space
+-----------------------------------------------+
| TEXT (code) - SHARED |
+-----------------------------------------------+
| DATA + HEAP - SHARED |
| (global vars, malloc'd memory, objects) |
+-----------------------------------------------+
| Stack T1 | Stack T2 | Stack T3 |
| (private) | (private) | (private) |
+-----------------------------------------------+
Each Thread has its own:
- Stack (local variables, function call frames)
- Program Counter (where it is executing)
- CPU Registers (its own register snapshot)
- Thread ID (TID)
All threads in a process share:
- Code (text segment)
- Global variables (data segment)
- Heap memory
- Open file descriptors
- Signals and signal handlers
Threads go through the same states as processes:
[New] ──────► [Runnable] ◄──── [Waiting/Blocked]
│ ▲
│ scheduled │ I/O / lock
▼ │
[Running] ───────────────┘
│
▼
[Terminated]
User-level threads are managed entirely by a user-space library. The kernel sees only one process. They are fast to create and switch, but if one blocks on I/O, the whole process blocks.
Kernel-level threads are known to the OS. The kernel can schedule them independently on different cores. Modern systems (Linux, Windows, macOS) use kernel threads.
Many-to-One: One-to-One: Many-to-Many:
UU UU UU U U U UU UU UU
| | | | | | | |
[Kernel] [K][K][K] [K][K][K][K]
All user threads Each user thread M user threads map to
share one kernel maps to one kernel N kernel threads (M >= N)
thread (no true thread (true (flexible, used in some
parallelism) parallelism) POSIX implementations)
Linux implements the One-to-One model using clone() — every thread is a kernel thread that shares the parent's address space.
import threading
import time
def download_file(name, duration):
print(f"Starting download: {name}")
time.sleep(duration) # simulate network I/O
print(f"Finished download: {name}")
# Without threads: sequential, takes 1+2+3 = 6 seconds
# With threads: parallel, takes max(1,2,3) = 3 seconds
threads = []
for name, dur in [("file_a.zip", 1), ("file_b.mp4", 2), ("file_c.tar", 3)]:
t = threading.Thread(target=download_file, args=(name, dur))
threads.append(t)
t.start()
for t in threads:
t.join() # wait for all threads to finish
print("All downloads complete")
Python has a Global Interpreter Lock (GIL) — a mutex that allows only one thread to execute Python bytecode at a time. This means Python threads do NOT achieve true parallelism for CPU-bound tasks. However, they are still useful for I/O-bound tasks (networking, disk) because threads release the GIL while waiting for I/O.
For CPU parallelism in Python, use multiprocessing (separate processes) or concurrent.futures.ProcessPoolExecutor.
Because threads share memory, they can interfere with each other in dangerous ways. A data race occurs when two threads access the same variable concurrently and at least one is writing.
import threading
counter = 0 # shared variable
def increment():
global counter
for _ in range(100000):
counter += 1 # NOT atomic! read → add → write
t1 = threading.Thread(target=increment)
t2 = threading.Thread(target=increment)
t1.start(); t2.start()
t1.join(); t2.join()
print(counter) # Expected: 200000
# Actual: could be 143829 or 178001 — unpredictable!
The counter += 1 operation is three CPU instructions: READ, ADD, WRITE. If Thread 1 reads the value (say, 50000) and Thread 2 also reads it (50000) before either writes back, both write 50001 — and one increment is lost forever.
This is why synchronization (mutexes, semaphores) is essential — covered in the next lesson.
Google Chrome — each browser tab is a separate process (for crash isolation), but within each process, multiple threads handle:
Linux web servers (nginx) — uses an event-driven, single-threaded model per worker process, relying on non-blocking I/O rather than spawning threads per connection.
Java — java.lang.Thread and java.util.concurrent are foundational; the JVM maps Java threads 1:1 to OS kernel threads on Linux and Windows.
Windows — CreateThread() in Win32 API; .NET's System.Threading.Thread wraps it.
# Number of threads in a process
cat /proc/<PID>/status | grep Threads
# Show threads for all processes
ps -eLf | head -20
# htop: press H to toggle thread display
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises