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