Thread Learning

This commit is contained in:
e2hang
2025-12-31 12:49:32 +08:00
parent a047893756
commit 09dd277cee
4 changed files with 1092 additions and 0 deletions

319
Thread/Atomic.md Normal file
View File

@@ -0,0 +1,319 @@
哈哈,**行,这套并发三件套我们直接收官** 😄
你已经把 `<thread>``<mutex>` 啃完了,现在这个 `<atomic>` **是精华也是雷区**
我给你一份**能当“原子操作说明书”的完整速查版**。
---
# 一、`<atomic>` 是干嘛的?一句话版
> **`<atomic>` 用来做“无锁但安全”的共享小数据。**
关键词只有三个:
*
* 简单
* 高频
典型:计数器、标志位、状态机。
---
# 二、`std::atomic<T>` 基础
## 1⃣ 定义原子变量
```cpp
#include <atomic>
std::atomic<int> x{0};
```
### 支持的常见类型
* `int / bool / long`
* 指针
* 枚举
* trivially copyable 类型(有限)
---
## 2⃣ 读 / 写load / store
```cpp
x.store(10);
int v = x.load();
```
### 默认内存序
* `memory_order_seq_cst`(最安全、最慢)
### 返回值
* `store`:❌ 无
* `load`:✔ 返回值
---
## 3⃣ 原子赋值(像普通变量一样)
```cpp
x = 5;
int y = x;
```
✔ 语法糖
✔ 等价于 `store / load`
---
# 三、原子读改写(重点)
## 4⃣ `fetch_add` / `fetch_sub`
```cpp
int old = x.fetch_add(1);
```
### 语义
* 返回 **修改前的值**
* 然后再加
```cpp
x++; // 等价 fetch_add(1)
--x; // fetch_sub(1)
```
### 返回值
✔ 修改前的值
---
## 5⃣ `exchange()` —— 原子替换
```cpp
int old = x.exchange(42);
```
### 作用
* 原子地:
* old ← x
* x ← 42
### 返回值
✔ 旧值
---
## 6⃣ `compare_exchange_weak / strong`(最难)
### 用途
> **CASCompare And Swap**
```cpp
int expected = 10;
x.compare_exchange_strong(expected, 20);
```
### 行为
* 如果 `x == expected`
* `x = 20`
* 返回 `true`
* 否则
* `expected = x`
* 返回 `false`
### 返回值
`bool`
### weak vs strong
| 版本 | 特点 |
| -------- | ---------- |
| `weak` | 可能失败(用于循环) |
| `strong` | 不会伪失败 |
---
# 四、指针原子(很实用)
## 7⃣ `std::atomic<T*>`
```cpp
std::atomic<Node*> p;
```
### 常用操作
```cpp
Node* old = p.load();
p.store(new_node);
```
```cpp
p.compare_exchange_strong(old, new_node);
```
👉 无锁链表、对象切换神器
---
# 五、内存序(进阶但你必须知道)
> **默认你可以全用 `seq_cst`,不会错。**
### 常见枚举
```cpp
std::memory_order_relaxed
std::memory_order_acquire
std::memory_order_release
std::memory_order_acq_rel
std::memory_order_seq_cst
```
### 什么时候用?
| 场景 | 内存序 |
| --------- | ----------------- |
| 简单计数 | relaxed |
| 生产者 / 消费者 | acquire / release |
| 不想翻车 | seq_cst |
---
## 示例(生产者-消费者)
```cpp
data = 42;
flag.store(true, memory_order_release);
```
```cpp
while (!flag.load(memory_order_acquire));
use(data);
```
---
# 六、原子标志(最轻量)
## 8⃣ `std::atomic_flag`
```cpp
std::atomic_flag f = ATOMIC_FLAG_INIT;
```
### 操作
```cpp
f.test_and_set(); // 返回旧值
f.clear();
```
✔ 自旋锁
✔ 最底层
---
# 七、等待 / 通知C++20
## 9⃣ `wait / notify_one / notify_all`
```cpp
x.wait(0);
x.store(1);
x.notify_one();
```
### 作用
* 原子级别的条件变量
* 无 mutex
### 返回值
❌ 无
---
# 八、完整 API 总表(收藏)
| API | 作用 | 返回值 |
| --------------------------- | ------- | ---- |
| `atomic<T>` | 原子变量 | — |
| `load()` | 原子读 | T |
| `store()` | 原子写 | void |
| `exchange()` | 替换 | T |
| `fetch_add()` | 加 | T |
| `fetch_sub()` | 减 | T |
| `compare_exchange_weak()` | CAS | bool |
| `compare_exchange_strong()` | CAS | bool |
| `atomic_flag` | 最小原子 | — |
| `test_and_set()` | 设置并返回旧值 | bool |
| `clear()` | 清空 | void |
| `wait()` | 等待 | void |
| `notify_one()` | 唤醒一个 | void |
| `notify_all()` | 唤醒全部 | void |
---
# 九、什么时候用 atomic一句判断法
> **如果共享数据:**
>
> * 类型简单
> * 操作简单
> * 不涉及多个变量一致性
👉 **atomic**
否则:
👉 **mutex**
---
# 🔥 十、新手 atomic 四大雷区(务必避开)
1**以为 atomic 能解决一切**(不能)
2**多个 atomic 组合 ≠ 原子整体**
3**乱用 relaxed**
4**atomic + 普通变量混用无同步**
---
# 十一、你现在的并发地图已经完整了
```text
thread → 干活
mutex → 防抢
atomic → 快而小
future → 拿结果
```
你现在完全可以:
* 看懂并发代码
* 写不翻车的并发
* 判断“该不该多线程”
---
如果你愿意,**最后一关**我可以带你做:
* 🔥 一个 **无锁队列atomic + CAS**
* 🔥 或把你之前那个拷贝工具 **升级成 atomic 进度条**
* 🔥 或讲 **C++ 内存模型白话终极版**
你点哪个,我收官。