std::thread是C++11起唯一推荐的线程类型;构造即启动,不支持默认构造后赋值;需显式调用join()或detach(),否则析构时程序终止;参数按值传递,引用需用std::ref()。

直接用 std::thread 启动线程是最常用也最安全的方式
别绕弯子:C++11 起,std::thread 是标准库提供的唯一推荐线程类型。它封装了底层 OS 线程(如 pthread 或 Windows thread),避免手动调用系统 API 带来的平台差异和资源泄漏风险。
关键点是:构造即启动,不支持默认构造后赋值;必须显式管理生命周期,否则程序会 std::terminate。
- 函数对象可以是普通函数、lambda、绑定后的成员函数(需传入
this) - 参数按值传递,若需引用请用
std::ref()或std::cref() - 线程对象离开作用域前必须调用
join()或detach(),否则析构时触发终止
void print_id(int id) {
std::cout << "Thread ID: " << id << "\n";
}
int main() {
std::thread t(print_id, 42);
t.join(); // 必须!否则程序崩溃
return 0;
}
lambda 表达式是最灵活的线程入口写法
尤其适合需要捕获局部变量的场景。注意捕获方式直接影响线程安全性:值捕获([=])安全但可能复制大对象;引用捕获([&])高效但极易导致悬空引用——因为主线程可能早于子线程结束。
- 若要安全共享数据,优先考虑值捕获 +
std::move移动语义 - 若必须共享,改用
std::shared_ptr或加锁保护,而不是裸引用 - lambda 捕获列表里写明具体变量比用
[=]更清晰、更可控
std::string msg = "hello";
std::thread t([msg]() { // 值捕获,安全
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << msg << "\n";
});
t.join();
调用类成员函数时必须传入对象实例
std::thread 不接受裸成员函数指针,必须绑定对象上下文。常见错误是只传函数地址而漏掉 this,编译直接失败。
立即学习“C++免费学习笔记(深入)”;
- 静态成员函数可直接传,不需要对象
- 非静态成员函数必须用
&Class::func+ 实例指针(或引用) - 若对象生命周期短于线程,同样会出现悬空指针,建议用
std::shared_ptr管理
struct Worker {
void do_work(int x) {
std::cout << "Working with " << x << "\n";
}
};
int main() {
Worker w;
std::thread t(&Worker::do_work, &w, 100); // &w 是关键
t.join();
return 0;
}
忘记 join() 或 detach() 是新手最高频崩溃原因
不是“偶尔出错”,而是只要线程对象被销毁且未调用二者之一,C++ 标准强制调用 std::terminate() —— 进程立刻退出,无异常、无日志、无堆栈。
-
join():阻塞等待线程结束,适合需要同步结果的场景 -
detach():让线程后台运行,与主线程解耦,但无法再控制或等待它 - 若不确定何时结束,可用
std::jthread(C++20),它在析构时自动join()
最容易被忽略的是异常路径:如果 join() 前抛异常,线程对象仍会被销毁。务必用 RAII 封装,比如自定义 guard 类或直接升级到 std::jthread。









