news 2026/8/6 7:22:26

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
线程函数中抛出的未捕获异常

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

文章目录

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

#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实现,你有需要的话我可以补充这部分代码。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/26 2:16:52

从“交易盲区”到“全链路在线”:如何构建穿透多级渠道的F2B2b协同网络?

当一场精心筹备的大促活动在战报大屏上画出昂扬的增长曲线时&#xff0c;品牌总部的后台往往呈现出另一种截然不同的景象。 为了接住瞬时涌入的订单波峰&#xff0c;企业通常需要紧急抽调数十名甚至更多的人员进行通宵录单。这些订单散落在微信聊天记录、Excel表格、电话录音以…

作者头像 李华
网站建设 2026/7/31 6:49:26

深度剖析SkyWalking:从内核原理到生产级全链路监控实战

1.概述 年底实在是太忙了&#xff0c;所以拖更了一个月&#xff0c;很是抱歉哈~ 言归正传&#xff0c;我们之前已经分享过&#xff1a;从入门到实践&#xff1a;玩转分布式链路追踪利器SkyWalking。这篇文章详细介绍了SkyWalking的核心概念、部署流程与接入实践。还不了解的请…

作者头像 李华
网站建设 2026/7/31 6:49:26

‌2026年职业预警:软件测试从业者如何应对AI对核心技能的重构?

被AI取代的五大传统测试技能‌ AI正以不可逆的速度接管软件测试中‌可标准化、高重复、低创造性‌的执行型任务。以下五类技能&#xff0c;已在2025–2026年进入“高危替代区”&#xff1a; 技能类别典型工作内容AI替代方式替代效率提升企业案例‌手动功能测试‌人工点击界面…

作者头像 李华
网站建设 2026/8/4 8:01:28

2026年CTO最想招的不是程序员,而是“懂业务的测试者”

技术变革下的测试者角色重塑 2026年&#xff0c;人工智能&#xff08;AI&#xff09;和云计算已深度融入软件开发全生命周期&#xff0c;CTO的招聘焦点正经历结构性转变。传统程序员虽仍是技术团队骨干&#xff0c;但CTO们更青睐那些能将业务逻辑与测试实践无缝融合的专业人才…

作者头像 李华