当前位置: 首页 > news >正文

多线程设计:join() 理解

join到底在干什么?(底层逻辑)

在操作系统的层面,join做了两件非常重要的事情:

  1. 阻塞调用者它会让调用join的那个线程(通常是主线程)进入“休眠”状态。操作系统会把它从 CPU 上切下来,直到子线程执行完毕。

  2. 清理资源每个线程在结束时,都会留下一些遗物(比如线程栈空间、退出状态码)。如果不用join也不用detach,这些资源会变成“僵尸线程”占用系统资源。join会负责回收这些遗物,确保系统干干净净。


那么我这就看着自己写的业务代码,思考:

class ChatServer { public: ChatServer(const ServerConfig &config); ~ChatServer(); void start(); void stop(); ///////////***//////////// bool isRunning(); std::string buildResponse(const std::string &message, bool success = false); // ..... private: std::thread _workerThread; ServerConfig _config; std::unique_ptr<httplib::Server> _chatServer; std::shared_ptr<ai_model_access_tech::ChatSDK> _chatSDK; std::atomic<bool> _isrunning = {false}; };
/*停止服务器运行*/ void ChatServer::stop() { // op0:判断服务器运行状态 if (_isrunning.exchange(false) == false) { bear::WARN("ChatServer 已停止运行!"); return; } // op1:停止服务器 if (_chatServer) { _chatServer->stop(); // 先让 listen 循环结束 } if (_workerThread.joinable()) { _workerThread.join(); // 在这里等待子线程结束,确保资源安全回收 bear::INFO("子线程已成功汇合 (Joined)"); } bear::INFO("ChatServer 成功停止运行~"); return; }

chatServer->stop()里面调用了join()这里是阻塞了主线程还是_workerthread

首先你可能觉得对象.方法()应该是“对象自己在做某事”。

但是:

在线程库的设计里:

  • 子线程:在 Lambda 表达式{ ... }内部默默耕耘,它根本不知道外面有一个叫_workerThread的变量在控制它。

  • 主线程拿着_workerThread这个“遥控器”。调用join()就像是按下了遥控器上的**“同步/等待”**键。

其次

我们可以把join想象成一场接力赛或者汇合点

  1. 子线程 (Worker):它像一个埋头跑步的运动员,它只管跑完listen函数。它并不知道主线程在干嘛。

  2. 主线程 (Main):它跑到了stop()函数里,看到了join()。这时候,主线程就像来到了一个关卡

  3. 关卡的规则:如果子线程还没跑完,主线程就必须在关卡前坐下休息(阻塞)

  4. 解锁时刻:子线程终于跑完了(listen结束,线程函数返回)。操作系统会发出信号:“子线程已到达!”

  5. 继续出发:主线程从关卡处起身,继续执行join()之后的代码(比如打印“服务器已停止”并退出程序)。

如果 不阻塞会发生什么?(可怕的后果)

如果你不调用join()也不调用detach(),C++ 的std::thread在析构时会直接导致程序崩溃(std::terminate)

为什么?因为 C++ 编译器非常死板:

  • 它看到main要结束了,准备销毁_chatServer对象。

  • 但它发现竟然还有一个子线程在跑,而且你没交代清楚是“等它(join)”还是“不要它了(detach)”。

  • 为了防止出现子线程访问已销毁内存的情况,编译器索性直接让程序自杀。

终极总结

  • join()的调用者:是谁写了这行代码,谁就被阻塞。(在本业务里,是主线程)。

  • join()的等待对象:是那个正在后台跑的子线程

  • 阻塞的本质:是为了让两个异步的灵魂,在程序终结前进行最后一次握手

所以,在stop()里的那行_workerThread.join(),实际上是主线程在说:“为了安全,我愿意等子线程最后这一小会儿。

http://www.jsqmd.com/news/615019/

相关文章:

  • 2025届最火的六大AI论文神器解析与推荐
  • 2026届学术党必备的五大AI辅助论文工具推荐
  • 光网络:弥合AI算力与消费之间的鸿沟
  • 一文搞懂 Cookie、Session 和 Token 的区别
  • 多格式文档批量字数统计与导出 Excel 备忘
  • Linux 下双击程序没反应?一条报错定位 root 启动问题
  • c++ grpc拦截器 c++如何实现grpc的客户端和服务端interceptor
  • Piggy_Packages V2026.1 帮助文档(四)WRF区域模式降尺度
  • 蓝桥杯——算法入门
  • 罗德与施瓦茨ZNB8功能概述
  • 3个突破性技巧:Figma设计数据结构化如何解决开发协作痛点
  • 空间智能技术赋能交通基础设施数字化提升方案
  • EF Core 10向量搜索扩展架构设计图泄露事件(内部PPT第7页已证实):这3个设计决策将重写.NET AI应用开发范式
  • 鸣潮游戏自动化终极指南:如何用ok-ww工具解放你的游戏时间
  • PHP容器化落地国产化替代的最后1公里:从Docker镜像构建、OpenEuler适配到等保2.0合规部署(含12项硬性检测项)
  • P4561 [JXOI2018] 排序问题
  • version attribute在html中必要吗_DOCTYPE替代说明【说明】
  • 知识点解释(1.1)
  • 不记命令也能排障:catpaw chat 实战手册俟
  • 贾子科学体系TMM三层结构定律全解:终结方法霸权,重构科学的“操作系统”
  • 2026届毕业生推荐的五大降重复率助手解析与推荐
  • 从田间到大屏只要1.8秒:PHP异步任务队列+Redis流式渲染农业可视化看板(实测QPS 1270+)
  • 如何在数据库中直接修改WordPress页面的发布时间_post_date编辑
  • OpenClaw 太难装了?试试 LangTARS:一行命令部署 + WebUI 管理面板,还能接入 Dify/Coze/nn??悠
  • PHP 8.9错误处理增强配置全解密(RFC #8721官方未公开的6个兼容陷阱)
  • 如何利用Prosurfactant蛋白C重组兔单抗研究肺发育机制?
  • 月入3W+!Java+YOLO接单变现全指南:10个可直接落地的AI视觉项目,全场景覆盖
  • 案例分析:学术文献综述 Agent Harness
  • 【Loom生产环境禁用清单】:这7个Spring Boot自动配置项正在 silently 杀死你的虚拟线程吞吐量
  • 为什么你的filter_var()在病历脱敏中彻底失效?——PHP 8.2+医疗场景下5类脱敏配置的权威基准测试报告