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

280 lines
4.8 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>` 全家桶说明**,不讲虚的,只讲:
* 干嘛用
* 怎么调
* 有没有返回值
* 什么时候该用 / 不该用
你看完这一份,再回头看你之前的代码,会突然“哦原来如此”。
---
# 一、`<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⃣ 手把手写一个 **线程池(真正工程级)**
你挑。