std::thread:多线程入门

创建线程、join 与 detach

商用

◎学完你会

1开一个线程干活,主线程等着它

std::thread t(f); 启动线程跑 f;t.join() 等它结束,t.detach() 让它后台自生自灭。

std::thread t(worker);
t.join(); // 等 t 结束
看两种生命周期管理。
线程对象必须 join 或 detach 之一,否则析构会 std::terminate。

2关键命令

写法含义
std::thread t(fn, args...);创建线程,用 fn(args...) 作为线程函数
t.join()阻塞等待 t 线程结束(回收资源)
t.detach()分离:线程转入后台,t 不再关联它
std::this_thread::sleep_for(…)当前线程睡眠指定时长
✅ join 一定别忘:线程对象析构时若既没 join 也没 detach,会调用 std::terminate 终止程序。

3线程生命周期:join vs detach

join:主线程停下来等它干完再继续——适合"必须等结果"。detach:线程在后台继续,主线程不等它——适合"后台任务/火忘掉";但 detach 后线程引用已销毁的局部变量会悬空。

void worker(){ for(int i=0;i<1000;i++) cout << i; } std::thread t(worker); t.join(); // 主线程等 worker 全部跑完 // 危险示例:detach 后 worker 用到即将销毁的局部变量 void bad(){ int x=5; std::thread t([&]{ while(true) cout<<x; }); t.detach(); } // x 提前销毁 → 悬空
要点:线程要访问的数据必须活得比线程久。detach 的线程生命周期不可控,访问栈上/局部数据极易悬空;能用 join 尽量 join,或用 async 管理生命周期(见 33.3)。

!易错点

① 忘 join 又忘 detach——线程对象析构触发 std::terminate。
② detach 后线程访问已销毁局部变量——悬空、未定义行为。
③ 给线程传引用没包 ref——std::thread t(f, x) 默认按值拷贝,改不了原变量;要 std::ref(x)。
④ 多线程同时改共享数据无锁——竞态(见 33.2/33.4)。

?跨学科:多线程,像"餐厅同时开几个窗口"

std::thread 像再开一个服务窗口(线程),多个窗口同时接待(并行干活),总吞吐更高。join 像"顾客在窗口前等这一单做完再走";detach 像"点完餐就离开,后厨做好自己放保温台",但没人盯着它,一旦它去拿已下架食材(销毁的变量)就出乱子。

核心教训:开多少窗口都要能收尾(join),别让没人管的窗口乱跑还引用着已撤掉的东西。

✎练一练

创建一个执行函数 worker 的线程,正确写法是?
std::thread t(worker); 用线程函数构造并启动线程。
t.join() 与 t.detach() 的区别是?
join 等待线程结束;detach 分离到后台、主线程不等(要当心悬空)。
线程对象既没 join 也没 detach 就析构,会发生什么?
线程对象析构时若还处于可关联状态,会 std::terminate。必须 join 或 detach 之一。