std::thread构造后必须detach或join,否则析构时调用std::terminate终止进程;传参默认拷贝,引用需std::ref;共享数据必须加锁,即使只读;线程名、优先级等需平台api。

std::thread 构造后必须 detach 或 join,否则程序崩溃
构造 std::thread 对象后不处理其生命周期,主线程退出时会调用其析构函数,而默认行为是调用 std::terminate() —— 直接终止整个进程,不会抛异常,也不打印堆栈。这是新手最常踩的坑。
- 必须在对象销毁前显式调用
join()(等待线程结束)或detach()(分离线程,交由系统托管) -
join()只能调用一次;重复调用是未定义行为;调用前需用joinable()判断 -
detach()后不能再调用join(),也不能再访问该std::thread对象的状态 - 推荐优先用
join(),除非明确需要后台长期运行且不关心完成时机(如日志刷盘线程)
传参到线程函数时,值传递和引用传递行为完全不同
std::thread 构造时对参数做**完美转发**,但所有参数都会被拷贝(或移动)进线程私有存储,原始变量不受影响。想传引用?必须套一层 std::ref(),否则你以为的“引用”其实是副本。
- 直接传
int x→ 线程里拿到的是x的拷贝,改它不影响主线程的x - 传
std::ref(x)→ 线程里操作的是同一块内存,需确保x的生命周期长于线程执行时间 - 传指针(如
&x)看似可行,但本质仍是值传递——传的是地址值,仍需手动保证对象不销毁 - lambda 捕获同理:
[x]()是值捕获,[&x]()是引用捕获,后者风险更高
int value = 42;
std::thread t([&value]() { value++; }); // 危险!主线程可能已析构 value
t.join(); // 若此时 value 已出作用域,UB
线程间共享数据必须加锁,不能靠“我只读不写”侥幸
即使多个线程只读同一个变量,只要该变量可能被其他线程修改,就必须同步。C++ 标准不保证读操作的原子性(除非是 std::atomic 类型),且编译器/CPU 可能重排指令、缓存不一致,导致看到过期值甚至崩溃。
- 普通
int、std::string等类型,读写都需保护;不要假设“只读就安全” - 首选
std::mutex+std::lock_guard,自动管理锁生命周期 - 避免手动
lock()/unlock(),容易遗漏或异常跳过 - 注意死锁:按固定顺序获取多个锁;或用
std::scoped_lock(C++17 起)同时锁多个互斥量
std::thread 不支持线程名、优先级等系统级控制
std::thread 是可移植抽象层,标准没规定如何设名称或调度策略。Linux 下可用 pthread_setname_np(),Windows 用 SetThreadDescription(),但这些都不是 C++ 标准接口,得自己封装并判断平台。
立即学习“C++免费学习笔记(深入)”;
- 调试时看不到线程名?不是你代码问题,是标准库故意没提供
- 想调高某线程优先级?必须用平台 API,且需权限(Linux 上通常要
cap_sys_nice) - 线程局部存储用
thread_local关键字即可,这个是标准且跨平台的 - 更复杂的线程池、任务调度需求,建议直接用
std::jthread(C++20)、boost::thread或第三方库如folly::Executor
std::thread,而在于数据怎么流、锁怎么分、生命周期谁管、错误怎么收。写完 t.join() 不代表万事大吉,得盯着每一份共享状态的归属和时效。







