thread
std::thread 是 C++11 引入的线程类,用于创建和管理原生线程。它让 C++ 程序可以并发执行多个任务,从而更好利用多核 CPU。
和早期平台相关线程 API 相比,std::thread 提供了跨平台、类型安全且更现代的接口模型。
头文件与基本特征
使用线程时,通常包含:
#include <thread>
主要特征:
| 特征 | 说明 |
|---|---|
| 作用 | 启动并管理一个执行线程 |
| 所有权 | thread 对象拥有线程句柄 |
| 是否可拷贝 | 不可拷贝 |
| 是否可移动 | 可移动 |
| 生命周期要求 | 可 join 的线程在析构前必须 join() 或 detach() |
基本用法
创建线程最常见的方式:
#include <iostream>
#include <thread>
void work() {
std::cout << "worker running\n";
}
int main() {
std::thread t(work);
t.join();
return 0;
}
join() 会等待线程执行结束,是最常见的收尾方式。
也可以直接传 lambda:
std::thread t([] {
// do something
});
t.join();
交互演示(MDX + React)
下面这个演示面板用于可视化 thread 的状态流转:启动、运行、完成、join、detach、move。
std::thread 生命周期演示
模拟线程对象从启动到 join/detach 的典型状态流转。
最近操作
- 初始化: thread 对象为空,不可 join
join 与 detach
join()
join() 会阻塞当前线程,直到目标线程执行结束:
std::thread t([] {
// long task
});
t.join();
调用后,线程句柄被回收,t.joinable() 变为 false。
detach()
detach() 会把线程与 thread 对象分离,线程在后台继续运行:
std::thread t([] {
// background task
});
t.detach();
分离后不能再 join(),并且要确保后台线程访问的资源在其运行期间仍有效。
joinable()
joinable() 用于判断线程对象当前是否还关联着可 join 的线程:
std::thread t([] {});
if (t.joinable()) {
t.join();
}
在写通用线程清理逻辑时,joinable() 非常重要。
move 语义
std::thread 不可拷贝,但可移动:
#include <thread>
int main() {
std::thread t1([] {});
std::thread t2 = std::move(t1);
if (t2.joinable()) {
t2.join();
}
return 0;
}
移动后,原对象 t1 不再拥有线程句柄。
线程 ID 与并发信息
获取线程 ID:
#include <iostream>
#include <thread>
int main() {
std::thread t([] {
std::cout << std::this_thread::get_id() << '\n';
});
std::cout << t.get_id() << '\n';
t.join();
}
获取硬件并发提示值:
unsigned int n = std::thread::hardware_concurrency();
它只是建议值,不保证精确。
参数传递
线程函数参数默认按值复制。如果要传引用,需要 std::ref:
#include <functional>
#include <thread>
void increment(int& x) {
++x;
}
int main() {
int value = 0;
std::thread t(increment, std::ref(value));
t.join();
}
休眠与让出执行权
常用工具在 <thread> 与 <chrono>:
#include <chrono>
#include <thread>
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::yield();
sleep_for 让当前线程休眠一段时间,yield 提示调度器可切换到其他线程。
常见陷阱
- 忘记
join()或detach():如果thread析构时仍是 joinable,程序会调用std::terminate。 detach()后访问悬空数据:后台线程引用了已经销毁的对象。- 数据竞争:多个线程同时读写共享变量却没有同步措施(需配合
mutex、原子变量等)。 - 过度创建线程:线程本身有开销,不应把极小任务拆成大量线程。
与 mutex / future 的关系
thread负责“并发执行”。mutex负责“并发访问同步”。future/promise负责“跨线程结果传递”。
三者组合是 C++11 多线程编程的基础模型。
小结
std::thread 是 C++11 并发的入口类型。掌握线程创建、join/detach、joinable、参数传递和移动语义后,就能建立稳定的线程生命周期管理习惯,再进一步配合 mutex 与 future 完成更完整的并发设计。