进程和线程以及异常信号捕获堆栈

本文探讨了进程和线程的区别,指出进程是虚拟概念,由task_struct管理,而线程是执行实体。重点讲解了线程有自己的堆栈空间及异常捕获中信号处理函数的位置。通过实例解析异常来源并追踪堆栈信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

进程和线程

进程是管理者由task_struct进行统一管理
其实一个进程对应着一个task_struct
线程是真实处理任务的,单线程来讲,其本身就是一个进程
线程有自己的堆栈空间
通过ulimit -a可以看到线程栈空间的限制为8192kb

所以当你创建一个线程时会开辟出自己的空间,线程之间访问内存是由task_struct实现的。
所以一个进程内的线程是可以访问另外一个线程的变量(锁暂且不提)

下面在来说下异常捕获

捕获异常需要注册信号
最简单的是signal函数signal(int, void(*)(int)),异常信号是SIGABRT
注册意味着内核收到进程内某一线程触发的信号时会调用该函数做后续处理,当然也存在默认处理方式
当内核收到异常信号,会触发注册过的回调,此时执行该回调的就是出现问题的线程,所以获取的堆栈也为该线程的堆栈信息。

本文重点是想说明进程是虚拟的,线程是实体,以及捕获信号时的函数执行位置
因为有些人会困惑自己注册了异常捕获函数,但获得的堆栈信息是否为出现问题的线程堆栈

下面给出一例捕获异常的函数堆栈信息
在这里插入图片描述
此处是由多free了一次导致的异常。
所以问题点可以直接找析构函数,查看哪个析构导致的。
如果不用这种方法来查看在哪多free了,估计时间要消耗很久

### Java 线程异常处理最佳实践 在多线程环境中,未被捕获异常可能会导致难以调试的问题。为了确保应用程序的稳定性可靠性,在Java中应采用合适的线程异常处理机制。 当Thread执行的任务抛出了未捕获异常,默认情况下JVM会打印堆栈跟踪到标准错误流并终止该线程。然而,这并不是一种优雅的方式去应对运行期发生的意外情况。因此建议采取如下措施: 对于实现了`Runnable`接口的情况,可以在run()方法内部手动try-catch任何可能产生的受检或不受检异常,并记录日志或者通知其他组件以便进一步处理[^1]。 如果使用的是更高层次的并发工具比如Executor框架,则可以通过实现`ThreadPoolExecutor`中的afterExecute(Runnable r, Throwable t)钩子函数来进行全局性的异常捕捉;另外还可以利用Future.get()获取异步调用的结果时也会抛出ExecutionException包装原始异常,从而有机会对外暴露底层问题的存在[^2]。 值得注意的是,InterruptedException是一个特殊的checked exception,它表示当前正在等待、休眠或其他阻塞操作被另一个线程中断。每当接收到此类信号后应当立即响应而不是忽略掉——要么重新设置中断状态(即调用interrupt()),要么传递给更高级别的逻辑层直至到达最顶层由其决定是否退出整个进程[^4]。 ```java // 使用 try-catch 块包裹 run 方法体内的代码 @Override public void run(){ try { // 可能发生异常的操作... } catch (Throwable t){ logger.error("Uncaught exception occurred", t); } } ``` 此外,自定义UncaughtExceptionHandler也是一种有效的方案,允许开发者指定特定于某个线程实例的行为模式来处置那些既没有显式声明也没有局部解决过的突发状况。只需重写handleException(Thread t, Throwable e)即可定制化反应流程[^3]。 最后提醒一点,尽管RuntimeException及其子类属于unchecked exceptions范畴无需强制要求程序员做额外预防工作,但从长远来看还是应该尽可能减少它们的发生频率以降低潜在风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值