优雅处理段错误

简介: 摘要:某些进程在结束前必须要处理一些额外的过程才能结束,尤其是数据存储的模块,进程停止前为保证数据的完整性可能要做一些事情,如果发生段错误,这时就需要先截获segv信号,处理完后再让程序出core一般进程收到段错误信号默认是dump core文件然后退出,但有些进程在退出时需要处理额外的过程才能结束,这时就不能让信号执行默认的动作了,我们就需要截获段错误信号,然后在信号处理函数中处理额外过程,我们称之为other_function,但是我们处理完后其实还是需要让程序core出来,以便知道是哪儿出问题了。

摘要:某些进程在结束前必须要处理一些额外的过程才能结束,尤其是数据存储的模块,进程停止前为保证数据的完整性可能要做一些事情,如果发生段错误,这时就需要先截获segv信号,处理完后再让程序出core
一般进程收到段错误信号默认是dump core文件然后退出,但有些进程在退出时需要处理额外的过程才能结束,这时就不能让信号执行默认的动作了,我们就需要截获段错误信号,然后在信号处理函数中
处理额外过程,我们称之为other_function,但是我们处理完后其实还是需要让程序core出来,以便知道是哪儿出问题了。
基础知识预备:
1.对线程而言,有三种信号类型:异步信号,同步信号,定向信号。其中异步信号是指传递给某些解除了对该信号的阻塞的线程的信号,同步信号是指传递给引发该信号的线程的信号,定向信号是指由pthread_kill函数发送给指定线程的信号。像SIGSEGV(段错误信号),SIGPFE(浮点错误)这样的错误信号就是同步于引发他们的线程的,因为引发这些信号的线程将等待信号处理程序处理完成后才能继续进行,这样的信号只能由本线程处理,而其他信号因为不与特定的线程相关,所以他们是异步的,例如其他进程给本进程发送的信号。如果有几个线程都解除了对同一个异步信号的阻塞,当有信号到达时,线程运行系统就从中选取一个来处理。
2.对于SIGSEGV信号,如果是由进程段错误导致的,则只能设定信号处理函数,不能阻塞或忽略,如果有是由别的进程发送的,则可以阻塞或忽略。
我们考虑了大概三个方案:
方案1:直接设置信号处理函数,在信号处理函数中处理other_function,处理完后再signal(SIGSEGV,SIG_DFL),这看起来比较完美,但实际上有锁的问题。如果出现段错误的线程中使用了锁,在没有解锁之前发生段错误,other_function中也使用了同一个锁,则容易出现死锁,造成进程hang住。other_function中无锁时此方案比较简单易行。
方案2:其他线程阻塞信号,由专有线程处理段错误信号。这个不可行,因为我们之前说了,段错误信号如果由进程产生则不能被阻塞或忽略
方案3:直接设置信号处理函数,但使用专有线程处理other_function。接到段错误信号后调用信号处理函数,信号处理函数中设置开始处理标记,然后定期检查专有线程是否处理完,专有线程定期检查开始处理标记,发现设定了就开始处理other_function,处理完之后设置处理完标记,然后推出。信号处理函数中定期检查处理完标记,发现一旦被处理完了则再signal(SIGSEGV,SIG_DFL),然后退出,等待出core。
这个方案也会出现方案1中的死锁问题,但是此时的死锁是两个线程之间的死锁,而不是同一个线程的死锁,所以是可以处理的,信号处理函数中设置一个超时时间即可,即信号处理函数发现专有线程太久没有处理完other_function就知道出现死锁了,这时没辙了,直接signal(SIGSEGV,SIG_DFL),让程序出core完事,由于这种可能是比较少的,所以是可以接受的。
另外一个问题是:如果other_function中本身也出core就比较囧了,此时可以在信号处理函数中做判断,如果开始处理标记已设定,说明已经已经在处理core了,再进来就直接signal(SIGSEGV,SIG_DFL),让程序出core了事
说的比较乱,直接看代码吧

  1. #include <stdint.h>
  2. #include <stdio.h>
  3. #include <pthread.h>
  4. #include <stdlib.h>
  5. #include <unistd.h>
  6. #include <signal.h>
  7. #include <string.h>
  8. volatile bool begin_segv_handle=false;
  9. volatile bool already_handle_other_function=false;
  10. void segv_handler(int signo);
  11. void * core_thread(void *args) {
  12.         int i=0;
  13.         while(1) {
  14.                 printf("in core thread\n");
  15.                 sleep(1);
  16.                 if(i++>2) {
  17.                         strcpy(NULL,"abc");
  18.                 }
  19.         }
  20.         return NULL;
  21. }
  22. void * other_function_thread(void *args) {
  23.         int i=0;
  24.         while(1) {
  25.                 printf("in other_function_thread\n");
  26.                 if(begin_segv_handle) {
  27.                         printf("set already_handle_other_function\n");
  28.                         already_handle_other_function = true;
  29.                         break;
  30.                 }
  31.                 sleep(1);
  32.         }
  33.         return NULL;
  34. }
  35. void segv_handler(int signo) {
  36.         printf("in segv_handler\n");
  37.         if(begin_segv_handle) {
  38.                 signal(SIGSEGV,SIG_DFL);
  39.                 return ;
  40.         }
  41.         begin_segv_handle = true;
  42.         int i=0;
  43.         while(1) {
  44.                 if(i++>10) {
  45.                         break;
  46.                 }
  47.                 if(already_handle_other_function){
  48.                         break;                
  49.                 }
  50.                 sleep(1);
  51.                 
  52.         }
  53.         signal(SIGSEGV,SIG_DFL);
  54. }
  55. int main(void)
  56. {
  57.         signal(SIGSEGV,segv_handler);
  58.         pthread_t tid_core_thread=0UL,tid_other_function_thread=0UL;
  59.         pthread_create(&tid_core_thread,NULL,core_thread,NULL);
  60.         pthread_create(&tid_other_function_thread,NULL,other_function_thread,NULL);
  61.         pthread_join(tid_core_thread,NULL);
  62.         pthread_join(tid_other_function_thread,NULL);
  63.         return 0;
  64. }
目录
相关文章
|
8月前
|
机器学习/深度学习 人工智能 自然语言处理
人工智能在虚拟客服中的关键作用:提升交互体验与服务效率
人工智能在虚拟客服中的关键作用:提升交互体验与服务效率
498 90
|
存储 固态存储 Java
用软硬协同设计下的飞天盘古降低存储系统开销
历经 15 载,如今的飞天盘古系统已迭代至第三代,数千万行代码和 1,000 余项专利,从大规模、到高性能、到高效能的分布式存储系统的演进,更高效地让数据中心成为一台计算机。
140259 142
用软硬协同设计下的飞天盘古降低存储系统开销
|
Java C++
jni传递对象
【5月更文挑战第4天】
158 2
|
Java API Android开发
Android中Binder在项目中的具体使用详解
Android中Binder在项目中的具体使用详解
334 0
|
存储 程序员 C++
在C++语言中string-vector的字符串作用类型
在C++语言中string-vector的字符串作用类型
271 0
|
Linux 程序员 C语言
Vs code写C语言代码配置(超详细超基础)
写在前面: 近期不是重新温习一下C语言吗,也给自己升级换代一下编辑器,最初我一直用Dev c++ 写的C语言,因为没想往深的学习C语言,也不会去写什么大的项目,所以这个编辑器也是可以用,但是目前认真学习,发现那个东西真的适合初学者,对于我这种懒人不适合,项目代码管理起来很麻烦,所以一气之下我直接鸟枪换炮,整个大家伙——vs,但是vs真的太大了,而且默认装在C盘,我这破电脑小内存扛不住,所以就研究了一下vs code,下面就本人安装经验给新学者讲解如何安装。
1094 0
|
Unix Linux C语言
【C/C++ 跳转函数】setjmp 和 longjmp 函数的巧妙运用: C 语言错误处理实践
【C/C++ 跳转函数】setjmp 和 longjmp 函数的巧妙运用: C 语言错误处理实践
279 0
|
关系型数据库 MySQL 数据库
如何在一个系统下同时运行两个甚至多个MYSQL数据库
如何在一个系统下同时运行两个甚至多个MYSQL数据库
1610 0
如何在一个系统下同时运行两个甚至多个MYSQL数据库
|
算法 搜索推荐 测试技术
冒泡排序:理解、实现与性能优化
冒泡排序:理解、实现与性能优化
303 0
【数据结构】双向链表中删除节点的方法实现(代码+详解)
【数据结构】双向链表中删除节点的方法实现(代码+详解)
534 0