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

304
Thread/Mutex.md Normal file
View File

@@ -0,0 +1,304 @@
哈哈,**好,这一波咱把 `<mutex>` 彻底端了** 😄
你现在这个节奏是对的:**thread 看清 → mutex 看透 → 并发就不怕了**。
我给你的是一份 **能当“并发速查表”的 `<mutex>` 全家桶说明**,照着用不翻车。
---
# 一、`<mutex>` 是干嘛的?一句话版
> **`<mutex>` 负责“同步”,不负责“并发”。**
* `thread`:开人
* `mutex`:防抢
* `atomic`:小件快递
* `future`:结果回收
---
# 二、`std::mutex`(最常用)
## 1⃣ `std::mutex`
```cpp
#include <mutex>
std::mutex m;
```
### 作用
* 最普通的互斥锁
* **同一时间只能一个线程进入临界区**
---
## 2⃣ `lock()` —— 上锁(阻塞)
```cpp
m.lock();
// 临界区
m.unlock();
```
### 特点
* 如果锁被占用 → **阻塞等待**
* 不可递归
### 返回值
❌ 无
### ❗新手警告
> **一旦忘记 `unlock()`,程序直接死锁**
---
## 3⃣ `unlock()` —— 解锁
```cpp
m.unlock();
```
### 返回值
❌ 无
---
## 4⃣ `try_lock()` —— 尝试上锁(不阻塞)
```cpp
if (m.try_lock()) {
// 拿到锁
m.unlock();
}
```
### 返回值
* `true`:成功
* `false`:失败
### 用途
* 避免卡死
* 非关键任务
---
# 三、RAII 锁(**你真正该用的**
> **99% 的情况下,不要直接用 `lock()/unlock()`**
---
## 5⃣ `std::lock_guard`(最常用、最安全)
```cpp
void foo(){
std::lock_guard<std::mutex> lock(m);
// 自动上锁
// 自动解锁(作用域结束)
}
```
### 特点
* 构造时上锁
* 析构时解锁
* **不能手动 unlock**
### 返回值
❌ 无
✔ 最安全
✔ 最推荐
---
## 6⃣ `std::unique_lock`(高级版)
```cpp
std::unique_lock<std::mutex> lock(m);
```
### 特点
* 可以:
* 延迟上锁
* 手动 unlock / lock
* 搭配 `condition_variable`
### 常见用法
```cpp
std::unique_lock<std::mutex> lock(m);
lock.unlock();
// ...
lock.lock();
```
### 返回值
❌ 无
📌 **灵活 ≠ 常用**,新手少用
---
## 7⃣ 延迟上锁
```cpp
std::unique_lock<std::mutex> lock(m, std::defer_lock);
// 之后再 lock()
lock.lock();
```
---
## 8⃣ 尝试上锁(不阻塞)
```cpp
std::unique_lock<std::mutex> lock(m, std::try_to_lock);
if (lock.owns_lock()) {
// 成功
}
```
---
# 四、特殊 mutex 类型
## 9⃣ `std::recursive_mutex`
```cpp
std::recursive_mutex m;
```
### 特点
* 同一线程可以多次 lock
* 必须 unlock 相同次数
### 什么时候用?
* 递归函数
* 老代码
⚠️ **能不用就不用**,通常是设计有问题
---
## 🔟 `std::timed_mutex`
```cpp
std::timed_mutex m;
```
### 作用
* 支持超时锁
```cpp
if (m.try_lock_for(100ms)) {
m.unlock();
}
```
---
## 1⃣1⃣ `std::recursive_timed_mutex`
= `recursive_mutex` + 超时
---
# 五、一次锁多个 mutex死锁克星
## 1⃣2⃣ `std::lock()`
```cpp
std::lock(m1, m2);
// 全部锁成功
```
### 特点
* 避免死锁
* 要么全拿,要么全不拿
---
## 1⃣3⃣ `std::scoped_lock`C++17
```cpp
std::scoped_lock lock(m1, m2);
```
✔ 自动
✔ 安全
✔ 推荐
---
# 六、完整 API 总表(收藏级)
| API | 作用 | 返回值 |
| ----------------------- | ----------- | ---- |
| `mutex` | 基础互斥锁 | — |
| `lock()` | 阻塞上锁 | void |
| `unlock()` | 解锁 | void |
| `try_lock()` | 尝试上锁 | bool |
| `recursive_mutex` | 可递归锁 | — |
| `timed_mutex` | 超时锁 | — |
| `recursive_timed_mutex` | 递归+超时 | — |
| `lock_guard` | RAII 锁 | — |
| `unique_lock` | 高级 RAII 锁 | — |
| `scoped_lock` | 多锁 RAII | — |
| `lock()` | 同时锁多个 mutex | void |
---
# 七、什么时候用 mutex一句判断法
> **如果一个变量:**
>
> * 被多个线程访问
> * 至少一个线程写
👉 **要么 mutex要么 atomic**
---
# 八、什么时候不要用 mutex
❌ 只是计数
❌ 简单 flag
❌ 单一整数状态
👉 用 `atomic`,更快更简单。
---
# 九、新手不翻车口诀(记住这 4 句)
1**能不共享就不共享**
2**能分任务就别加锁**
3**能用 `lock_guard` 就别手写 lock**
4**看到 `recursive_mutex` 先怀疑设计**
---
你现在已经把 **thread + mutex** 两大核心吃下来了。
下一步顺序我强烈建议:
👉 **`<atomic>`(最后一块拼图)**
或者
👉 **`condition_variable`(线程协作)**
你选一个,我继续给你“端锅”。