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

305 lines
4.7 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.

哈哈,**好,这一波咱把 `<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`(线程协作)**
你选一个,我继续给你“端锅”。