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

279
Thread/Thread.md Normal file
View File

@@ -0,0 +1,279 @@
哈哈哈哈,**太正常了**,这玩意儿本来就反直觉 😄
行,我给你一份**能当速查表用的 `<thread>` 全家桶说明**,不讲虚的,只讲:
* 干嘛用
* 怎么调
* 有没有返回值
* 什么时候该用 / 不该用
你看完这一份,再回头看你之前的代码,会突然“哦原来如此”。
---
# 一、`<thread>` 到底提供了什么?
严格来说 `<thread>` **只解决三件事**
1. 创建线程
2. 控制线程生命周期
3. 获取线程身份 / 状态
👉 **不负责:**
* 返回值
* 同步
* 通信
那些是 `<future>``<mutex>``<atomic>` 的活。
---
# 二、`std::thread`(核心中的核心)
## 1⃣ 构造线程(创建并立刻运行)
```cpp
#include <thread>
void foo(int x) {}
std::thread t(foo, 10);
```
### 本质
* 创建 OS 线程
* 立刻执行 `foo(10)`
### 参数规则
* **按值拷贝**
* 要引用必须用 `std::ref`
```cpp
int x = 10;
thread t(foo, ref(x));
```
### 返回值
**没有**
(线程函数的返回值会被丢弃)
---
## 2⃣ `join()` —— 等线程干完
```cpp
t.join();
```
### 作用
* 阻塞当前线程
* 直到 `t` 执行完
### 返回值
❌ 无
### 必须记住的铁律
> **一个 `std::thread`
> 要么 `join()`,要么 `detach()`,否则程序直接 `std::terminate()`**
---
## 3⃣ `detach()` —— 放生线程(慎用)
```cpp
t.detach();
```
### 作用
* 线程变成后台线程
* 主线程不再管它
### 返回值
❌ 无
### 什么时候能用?
* 日志
* 心跳
* 不依赖任何外部对象
### 新手忠告
> **90% 的 `detach()` 都是 bug**
---
## 4⃣ `joinable()` —— 能不能 join
```cpp
if (t.joinable()) {
t.join();
}
```
### 什么时候 false
* 已 join
* 已 detach
* 默认构造的 thread
---
## 5⃣ `get_id()` —— 线程 ID
```cpp
std::thread::id id = t.get_id();
```
### 用途
* 调试
* 日志
* 判断是不是同一个线程
---
## 6⃣ `std::this_thread::get_id()`
```cpp
auto id = std::this_thread::get_id();
```
👉 获取**当前线程**的 ID
---
# 三、线程“辅助函数”(非常常用)
## 7⃣ `sleep_for()` —— 休眠一段时间
```cpp
#include <chrono>
using namespace std::chrono_literals;
std::this_thread::sleep_for(100ms);
```
### 作用
* 让当前线程休眠
### 返回值
❌ 无
---
## 8⃣ `sleep_until()` —— 睡到某个时间点
```cpp
auto t = chrono::steady_clock::now() + 1s;
std::this_thread::sleep_until(t);
```
---
## 9⃣ `yield()` —— 让出 CPU
```cpp
std::this_thread::yield();
```
### 作用
* 告诉调度器:
“我不急,你先跑别人”
### 用途
* 自旋锁
* 低优先级任务
---
# 四、`hardware_concurrency()` —— CPU 有多少核?
```cpp
unsigned n = std::thread::hardware_concurrency();
```
### 返回值
* 建议线程数
* **可能是 0不保证**
👉 常见用法:
```cpp
int n = max(1u, thread::hardware_concurrency());
```
---
# 五、所有 `<thread>` API 一览表(重点)
| API | 作用 | 返回值 |
| ---------------------------- | ------- | ------------ |
| `thread(f, args...)` | 创建并运行线程 | — |
| `join()` | 等线程结束 | void |
| `detach()` | 放生线程 | void |
| `joinable()` | 能否 join | bool |
| `get_id()` | 线程 ID | `thread::id` |
| `this_thread::get_id()` | 当前线程 ID | `thread::id` |
| `this_thread::sleep_for()` | 休眠 | void |
| `this_thread::sleep_until()` | 睡到时间点 | void |
| `this_thread::yield()` | 让出 CPU | void |
| `hardware_concurrency()` | CPU 线程数 | unsigned |
📌 **没有一个 API 有“业务返回值”**
---
# 六、那“返回值”到底去哪了?
👉 **根本不在 `<thread>`**
你要记住这个分工:
| 需求 | 用什么 |
| ------ | ---------------- |
| 跑线程 | `std::thread` |
| 拿返回值 | `std::future` |
| 简单并发任务 | `std::async` |
| 同步 | `mutex / atomic` |
---
# 七、你现在可以这样理解(非常重要)
> **`std::thread` ≈ C 语言 `pthread_create`
> `std::async` ≈ “有返回值的线程函数”**
所以你刚才的崩溃是合理的 😂
你是拿 **pthread 的心态**,期待 **Java 的体验**
---
# 八、给你一条“永远不翻车”的使用准则
> **如果你想要返回值:
> ❌ 不要用 `std::thread`
> ✅ 用 `std::async`**
---
如果你愿意,下一步我可以帮你做三件事之一:
1⃣ 把你刚才那个项目 **改成 async 版本**
2⃣ 给你一份 **`<future>` 函数大全(和这份一样清楚)**
3⃣ 手把手写一个 **线程池(真正工程级)**
你挑。