Thread Learning
This commit is contained in:
304
Thread/Mutex.md
Normal file
304
Thread/Mutex.md
Normal 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`(线程协作)**
|
||||
|
||||
你选一个,我继续给你“端锅”。
|
||||
Reference in New Issue
Block a user