std::thread 构造后必须调用 join() 或 detach(),否则析构时触发 std::terminate;join() 阻塞等待线程结束,detach() 使线程后台运行但需避免访问已销毁资源;joinable() 为 false 后不可再调用 join()/detach()。

std::thread 构造后必须调用 join() 或 detach()
不处理线程对象生命周期会直接触发 std::terminate,程序异常终止,且无任何错误提示——这是新手最常踩的坑。
-
join()阻塞当前线程,等待目标线程结束;适用于需要同步结果或确保资源清理的场景 -
detach()使线程后台运行,与原std::thread对象解绑;但要注意: detached 线程里不能访问已销毁的栈变量或局部std::shared_ptr - 一旦调用过
join()或detach(),该std::thread对象就变成不可加入状态(t.joinable() == false),再次调用会抛std::system_error
std::mutex 加锁失败不会报错,但 std::lock_guard 不保证原子性
std::mutex::lock() 在已被占用时会阻塞,而非失败返回;而 std::lock_guard 只是 RAII 封装,它本身不解决竞争逻辑——它只管“进临界区时加锁、出作用域时解锁”,不关心你是否该进。
- 常见误用:
std::lock_guard<:mutex> lk(mtx);</:mutex>写在 if 分支外,导致本不该执行的代码也被锁保护 - 真正需要“尝试加锁”的场景(比如避免死锁或超时等待),得用
std::timed_mutex+try_lock_for() -
std::unique_lock才支持延迟加锁、条件变量配合等高级操作;std::lock_guard仅适合简单、确定要加锁的临界区
condition_variable 的 wait 必须配合 while 循环检查条件
用 if 替代 while 是经典陷阱:虚假唤醒(spurious wakeup)会导致线程跳过条件检查,直接执行后续逻辑,引发数据错乱。
- 正确写法永远是:
while (flag != expected_value) cond.wait(lk); -
wait()内部会自动调用lk.unlock(),挂起线程;被唤醒后重新加锁再返回,所以必须重检条件 - 注意:
notify_one()和notify_all()不保证唤醒顺序,也不保证立即执行——它们只是“发信号”,实际调度由 OS 决定
共享变量读多写少时,别急着上 mutex
对只读频繁、修改极少的全局状态(如配置项、开关标志),用 std::atomic<bool></bool> 或 std::atomic<int></int> 足够,比互斥锁轻量得多,且无上下文切换开销。
-
std::atomic默认提供 sequential consistency 语义,足够应对绝大多数场景 - 但注意:复合操作(如
counter++)不是原子的,即使counter是std::atomic<int></int>,也得用fetch_add() - 若涉及多个变量协同更新(比如同时改 status 和 data),
std::atomic无法替代 mutex,此时仍需锁或std::shared_mutex(C++17)
std::atomic_load 是几十纳秒,一次 mutex::lock() 可能上百纳秒起步,而虚假唤醒+条件重检带来的逻辑绕弯,往往比性能问题更难 debug。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











