Files
CWithClasses/Thread/readme.md
2025-12-31 00:39:23 +08:00

356 lines
5.2 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

好,这个问题问得**非常到位**。
我直接给你一份 **「线程 / 并发编程全景图」**,从**你现在的水平**一路铺到**系统级 / 工程级**,不糊、不玄、不跳步。
你可以把这条线当成:
> **C / C++ 程序员从“会用线程”到“能写并发系统”的路线图**
---
# 一、线程到底是什么(地基)
### 1⃣ 线程 vs 进程(必须先立住)
| 对象 | 是否独立地址空间 | 开销 | 通信 |
| -- | ---------- | -- | ------ |
| 进程 | ✅ 有 | 大 | IPC |
| 线程 | ❌ 共享进程地址空间 | 小 | 直接共享内存 |
👉 **线程共享:**
* 全局变量
* 堆内存
* 文件描述符
👉 **线程私有:**
*
* 寄存器
* 程序计数器
⚠️ **线程 = 并发的根源 + BUG 的源头**
---
# 二、线程基础 API你已经碰到的部分
## 2⃣ 线程生命周期
以 C++ 为例:
```cpp
std::thread t(func);
t.join();
```
完整状态流转:
```
创建 → 就绪 → 运行 → 结束
被抢占
```
---
## 3⃣ join / detach线程管理
| 操作 | 作用 |
| ---------- | ---------- |
| `join()` | 等线程结束 |
| `detach()` | 后台运行,无法再控制 |
⚠️ **一个线程只能 join 一次**
---
# 三、线程最核心的问题:数据竞争 💥
## 4⃣ 什么是数据竞争Race Condition
```cpp
int x = 0;
void f() {
x++; // ❌ 非原子操作
}
```
两个线程同时执行:
```
load x
add 1
store x
```
👉 结果可能是:
* 1
* 2
* 乱七八糟UB
📌 **没有同步 = 行为未定义**
---
# 四、同步原语(并发的骨架)
## 5⃣ 互斥锁Mutex——第一大杀器
```cpp
std::mutex m;
void f() {
std::lock_guard<std::mutex> lock(m);
x++;
}
```
### Mutex 解决什么?
* 保证 **临界区** 同一时间只有一个线程进入
### 常见变种:
* `mutex`
* `recursive_mutex`
* `timed_mutex`
* `shared_mutex`(读多写少)
---
## 6⃣ 死锁(锁的黑暗面)☠️
```cpp
lock(A);
lock(B);
```
另一线程:
```cpp
lock(B);
lock(A);
```
💀 **两人对视,程序永恒**
### 解决方法:
* 统一加锁顺序
* `std::lock()`
* 层级锁lock hierarchy
---
## 7⃣ 条件变量Condition Variable
👉 **“我等一个条件成立”**
```cpp
std::condition_variable cv;
std::mutex m;
bool ready = false;
void worker() {
std::unique_lock<std::mutex> lock(m);
cv.wait(lock, []{ return ready; });
}
```
用途:
* 生产者-消费者
* 线程间通知
⚠️ **必须配合 mutex 使用**
---
# 五、原子操作(无锁并发)
## 8⃣ `std::atomic`(你迟早会用)
```cpp
std::atomic<int> x{0};
x++;
```
特点:
* 无锁(可能是 CPU 指令)
* 不会数据竞争
### 内存序(进阶但重要):
* `memory_order_relaxed`
* `acquire / release`
* `seq_cst`
👉 **这是并发里最难的一块**
---
# 六、线程模型 & 执行结构
## 9⃣ 线程池(工程级必备)
问题:
* 线程创建很贵
解决:
```text
任务队列 + 固定数量线程
```
用途:
* Web 服务器
* 游戏引擎
* 编译器
---
## 🔟 任务 vs 线程(现代并发思想)
| 概念 | 含义 |
| -- | ---- |
| 线程 | 执行单元 |
| 任务 | 要做的事 |
C++
* `std::async`
* `std::future`
* `std::promise`
---
# 七、系统层线程(你会很喜欢)
## 1⃣1⃣ OS 级线程实现
### Linux
* `pthread_create`
* `futex`
* 调度器CFS
### Windows
* `CreateThread`
* `WaitForSingleObject`
👉 **C++ `std::thread` 本质是封装**
---
## 1⃣2⃣ 用户态线程(协程)
| 类型 | 是否 OS 线程 |
| ----------- | -------- |
| std::thread | 是 |
| 协程 | 否 |
特点:
* 切换快
* 不能抢占
* 需要调度器
例子:
* C++20 coroutine
* Go goroutine
* libco / boost::coroutine
---
# 八、并发的“终极敌人”
## 1⃣3⃣ 可见性 & 内存模型
问题:
```cpp
flag = true; // 线程 A
while(!flag) {} // 线程 B
```
⚠️ **可能死循环**
原因:
* CPU cache
* 编译器重排
解决:
* atomic
* mutex
* memory barrier
---
## 1⃣4⃣ 假共享False Sharing
```cpp
struct {
int a;
int b;
};
```
a / b 在同一 cache line
两个线程写不同变量 → 性能暴死
---
# 九、你这个阶段最推荐的学习顺序 ✅
结合你**超偏底层 + 喜欢 C**的特点,我给你一个**实操导向路线**
### 第一阶段(立刻)
* `std::thread`
* `join / detach`
* `mutex`
* 数据竞争概念
### 第二阶段
* 生产者-消费者
* 条件变量
* 死锁分析
### 第三阶段(爽点)
* `std::atomic`
* lock-free 计数器
* 内存序
### 第四阶段(硬核)
* pthread + futex
* 调度器原理
* 协程实现
---
# 十、一句话总结(你现在的位置)
> **你已经站在“并发编程”的门口了**
> 接下来学的不是“语法”,而是:
> 👉 **CPU、内存、调度、同步的真实世界**
如果你愿意,下一步我可以直接带你:
* **手写一个线程池C / C++**
***用汇编 + C 看 atomic 指令**
***画一张“并发 BUG 地狱图”**
你选一个,我陪你打到懂为止 😈