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

线程函数中抛出的未捕获异常

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

      • 崩溃原因分析
      • 修复后的完整代码
      • 关键修改说明
      • 运行结果示例
      • 总结

#include<iostream>#include<thread>#include<mutex>#include<vector>#include<stdexcept>intg_count=0;std::mutex g_mutex;voidincrementSafe(inttimes){for(inti=0;i<times;++i){// RAII:构造时加锁,析构时解锁(即使异常也会解锁)std::lock_guard<std::mutex>lock(g_mutex);// 模拟异常if(i==500){// 异常抛出时,lock的析构函数会被调用,自动解锁throwstd::runtime_error("意外异常");}g_count++;}}intmain(){constintthread_num=5;constinttimes_per_thread=1000;std::vector<std::thread>threads;try{for(inti=0;i<thread_num;++i){threads.emplace_back(incrementSafe,times_per_thread);}for(auto&t:threads){t.join();}}catch(conststd::exception&e){std::cout<<"捕获异常:"<<e.what()<<std::endl;}std::cout<<"最终count值:"<<g_count<<std::endl;return0;}

上篇文章中代码运行崩溃

崩溃原因分析

这段代码崩溃的核心原因是:线程函数中抛出的未捕获异常无法被主线程的catch捕获
C++ 线程的规则是:如果线程函数内部抛出异常且没有在线程内捕获,该异常会直接触发std::terminate()函数,导致整个程序强制终止(崩溃),主线程的try-catch完全无法拦截这种跨线程的异常。

虽然std::lock_guard的 RAII 特性确实能保证异常时解锁(这部分是正确的),但异常本身没有被处理,最终导致程序崩溃。

修复后的完整代码

下面是修复后的代码,核心思路是在线程函数内部捕获异常,避免异常逃逸出线程;同时保留原有的线程安全和 RAII 锁特性:

#include<iostream>#include<thread>#include<mutex>#include<vector>#include<stdexcept>intg_count=0;std::mutex g_mutex;voidincrementSafe(inttimes){try{// 线程内部捕获异常,避免异常逃逸for(inti=0;i<times;++i){// RAII:构造时加锁,析构时解锁(即使异常也会解锁)std::lock_guard<std::mutex>lock(g_mutex);// 模拟异常if(i==500){throwstd::runtime_error("意外异常");}g_count++;}}catch(conststd::exception&e){// 线程内处理异常,也可以记录日志、通知主线程等std::lock_guard<std::mutex>lock(g_mutex);// 加锁保证输出线程安全std::cout<<"线程内捕获异常:"<<e.what()<<std::endl;}}intmain(){constintthread_num=5;constinttimes_per_thread=1000;std::vector<std::thread>threads;// 创建并启动所有线程for(inti=0;i<thread_num;++i){threads.emplace_back(incrementSafe,times_per_thread);}// 等待所有线程执行完成for(auto&t:threads){if(t.joinable()){// 检查线程是否可join,避免重复joint.join();}}std::cout<<"最终count值:"<<g_count<<std::endl;return0;}

关键修改说明

  1. 线程内增加try-catch:在incrementSafe函数开头添加try块,捕获函数内抛出的所有异常,避免异常逃逸出线程导致程序崩溃;
  2. 线程安全的异常输出:异常信息输出时也加了互斥锁,避免多个线程同时输出导致乱码;
  3. 增加joinable()检查:防止因异常导致线程状态异常时重复join,提升代码健壮性;
  4. 移除主线程多余的try-catch:因为线程内的异常已被处理,主线程无需再捕获(如果需要主线程感知异常,可以用std::future,新手阶段先掌握线程内捕获即可)。

运行结果示例

运行后你会看到类似这样的输出(顺序可能因线程调度略有不同):

线程内捕获异常:意外异常 线程内捕获异常:意外异常 线程内捕获异常:意外异常 线程内捕获异常:意外异常 线程内捕获异常:意外异常 最终count值:2500

(每个线程执行到第500次时抛出异常,所以每个线程只执行了500次计数,5个线程总计 5×500=2500)

总结

  1. 核心崩溃原因:线程内未捕获的异常会触发std::terminate(),无法被主线程catch拦截;
  2. 关键修复手段:在线程函数内部捕获并处理异常,是新手阶段最稳妥的方式;
  3. RAII 锁的价值:即使抛出异常,std::lock_guard也会自动析构解锁,不会导致死锁,这部分原代码的设计是正确的。

如果需要让主线程感知到线程内的异常(而非仅在线程内处理),可以基于std::packaged_taskstd::future实现,你有需要的话我可以补充这部分代码。

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

相关文章:

  • 为什么35岁前没学AI,你仍有机会翻身?
  • 别再只写脚本了!测试工程师如何成为技术决策者
  • 震惊!这些免费工具能让开发效率提升200%:软件测试从业者的专业指南
  • ‌为什么AI安全测试成2026年刚需?——给软件测试从业者的专业深度解析
  • .net AI开发05 第九章 新增 RAG 文档处理后台服务 RagWorker 及核心流程
  • 量子计算+AI融合:开发者必须跟上的新浪潮
  • 【大模型训练】deepseek MTPpp阶段的输入内容哪里来
  • 地理信息科学(GIS)专业就业真相
  • 开发者创作必备工具清单:技术博客 / 教程 /内容全流程工具汇总
  • 面试官:既然 JWT 这么好,为什么大厂还在用 Session?
  • TCON板硬件调试小记
  • 一上午就面了4个前端岗,基本都给了二次机会
  • [特殊字符]JS 为什么能跑这么快?一文把 V8 “翻译官 + 加速器” 机制讲透(AST / 字节码 / JIT / 去优化)
  • 公司新来的前端虽然水,但比很多人明智
  • Excel信息函数全解析:ROWS、COLUMNS、AREAS、FORMULATEXT实战指南
  • 我算是见识到26年前端岗的面试难度了.....
  • MATLAB图像处理人脸识别(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码
  • 多表查询
  • React 那么多状态管理库,到底选哪个?如果非要焊死一个呢?这篇文章解决你的选择困难症
  • R 语言 - 基础入门
  • 小程序毕设选题推荐:基于微信小程序的驾校预约系统的设计与实现基于SpringBoot与微信小程序的驾校预约管理系统设计与实现【附源码、mysql、文档、调试+代码讲解+全bao等】
  • matlab人脸识别源码[有报告】(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码
  • 小程序毕设项目推荐-基于微信小程序的驾校预约与学习系统基于微信小程序的驾校预约系统的设计与实现【附源码+文档,调试定制服务】
  • 基于k-means聚类的图像区域分割[有报告]图像处理聚类区域分割(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码
  • 轨迹跟踪算法-基于神经网络NN或自适应神经模糊系统ANFIS优化模型预测控制MPC的自动驾驶车辆横向轨迹跟踪(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码
  • 交通警察检测数据集4327张VOC+YOLO格式
  • SAP ABAP SELECT语句完全指南
  • 遛狗不牵绳数据集1047张VOC+YOLO格式
  • 不想当背锅侠,这6款监控工具一定要会!(Zabbix、Prometheus等常见监控教程)
  • 吐血整理40个网络安全漏洞挖掘姿势,看完不信你还挖不到!