Repository navigation
Thread
Oğuzhan Düğüncü edited this page Dec 11, 2025
·
1 revision
A practical and deeply technical guide to std::thread, ownership semantics, move rules, false sharing, cache-line behavior, and high-performance concurrency patterns in C++.
⚡ Production-level explanations, clean diagrams, and benchmark-backed insights.
- Introduction
- Thread Lifecycle & Constructors
- Ownership Model
- Join vs Detach
- Move Semantics (The Dangerous Parts)
- False Sharing & Cache Lines
- Measuring Read vs Write Cost
- Safe Reuse Patterns
- Unsafe Patterns (Terminate Scenarios)
- Cheat Sheet
Modern C++ threads (std::thread) give you native, low-level control over OS threads with a strict ownership model:
- Threads are move-only
- They must be joined or detached
- Incorrect ownership transfer →
std::terminate() - Performance is heavily impacted by memory layout and cache-line behavior
std::thread t(func, arg1, arg2);std::thread t;joinable() == false
std::thread t2 = t; // compile errorstd::thread t2(std::move(t));A std::thread owns its OS thread.
- Ownership is unique
- Must be released via join/detach
- Waits for completion
-
joinable()becomes false
- Thread runs independently
-
joinable()becomes false
If a thread is joinable during destruction → terminate.
std::thread t;
t = std::thread(func);std::thread t(func);
t = std::thread(func2); // terminate()Move assignment checks:
if (this->joinable()) → terminate()
False sharing occurs when multiple threads write to variables on the same cache line.
struct room { int id, size; };
room rooms[N];8 objects * 8 bytes = 64 bytes → same cache line.
struct alignas(64) padded_room {
int id;
int size;
char pad[56];
};Your benchmark:
- Normal write: ~4.6s
- Padded write: ~1.1s
- Speedup: 4.1×
Reading is cheap.
Writing is expensive—especially when cores write to the same cache line.
Your experiments confirmed:
- Read-only: fast
- Write-only: slow unless padded
std::thread worker;
worker = std::thread(func1);
worker.join();
worker = std::thread(func2);
worker.join();std::thread t(func);
t = std::thread(func2); // terminate{
std::thread t(func);
} // terminatestd::thread t(func);
t = std::move(t); // terminatestd::thread t; t = std::thread(f);t.join();t.detach();- Move constructor
- Move assignment to joinable thread
- Destructor with joinable thread
- Self-move assignment
offset = address & 0x3F; // 0–63
line_id = address >> 6;