Thread Learning
This commit is contained in:
319
Thread/Atomic.md
Normal file
319
Thread/Atomic.md
Normal 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`(最难)
|
||||
|
||||
### 用途
|
||||
|
||||
> **CAS(Compare 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++ 内存模型白话终极版**
|
||||
|
||||
你点哪个,我收官。
|
||||
Reference in New Issue
Block a user