Lesson 03 — Thread & Concurrency
Thread vs Process, Concurrency vs Parallelism, và Race Condition.
1. Thread chia sẻ Address Space — nhưng Stack riêng
Sơ đồ dưới minh hoạ một Process với 2 Thread. Phần màu xanh/hồng là riêng của từng thread; phần nền là chia sẻ.
Kết luận: Thread nhẹ hơn process vì chỉ cần tạo stack mới (~8 KB – 8 MB), không cần sao chép toàn bộ address space.
Giao tiếp qua biến global/heap trực tiếp — không cần IPC như pipe hay socket.
Nhưng: chia sẻ là con dao hai lưỡi — một thread viết sai địa chỉ có thể corrupt dữ liệu thread khác.
2. Concurrency vs Parallelism — Minh họa Timeline
Chọn kịch bản để xem timeline thực thi của Thread A và Thread B.
3. Mô phỏng Race Condition — counter++
Hai thread cùng tăng counter++ 10 lần mỗi thread.
Kết quả mong đợi: 20. Nhưng với race condition, kết quả có thể khác.
Thread A
for i in 0..10:
rax = counter ← đọc
rax += 1 ← tăng
counter = rax ← ghi
rax = counter ← đọc
rax += 1 ← tăng
counter = rax ← ghi
Thread B
for i in 0..10:
rax = counter ← đọc
rax += 1 ← tăng
counter = rax ← ghi
rax = counter ← đọc
rax += 1 ← tăng
counter = rax ← ghi
60%
0
Mong đợi: 20 | Thực tế: —
Nhấn ▶ Chạy để mô phỏng...
4. Mô hình Threading: 1:1 vs M:N
1:1 (Kernel Thread)
User Thread ↔ Kernel Thread
U1 — U2 — U3
↕ ↕ ↕
K1 — K2 — K3
↕ ↕ ↕
Core1 Core2 Core1
↕ ↕ ↕
K1 — K2 — K3
↕ ↕ ↕
Core1 Core2 Core1
- Stack: 8 MB/thread
- Tạo: ~20 μs (syscall)
- Switch: ~1-10 μs (kernel)
- Max: ~32,768 thread
- Ví dụ: pthreads, Java thread
M:N (Go Goroutine)
M goroutine → N kernel thread
G1 G2 G3 G4 G5 G6
↕ ↕ ↕
K1 K2 K3
↕ ↕ ↕
Core1 Core2 Core3
↕ ↕ ↕
K1 K2 K3
↕ ↕ ↕
Core1 Core2 Core3
- Stack: 2 KB khởi đầu
- Tạo: ~1 μs (user space)
- Switch: ~100 ns (runtime)
- Max: hàng triệu goroutine
- Ví dụ: Go, Erlang, Java Loom
Xu hướng hiện đại: M:N (goroutine, virtual thread) — tạo 100,000 goroutine ≈ 200 MB RAM thay vì 800 GB (1:1 thread)