Files
CWithClasses/Thread/Atomic.md
2025-12-31 12:49:32 +08:00

320 lines
5.1 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.

哈哈,**行,这套并发三件套我们直接收官** 😄
你已经把 `<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++ 内存模型白话终极版**
你点哪个,我收官。