优雅处理段错误

摘要:某些进程在结束前必须要处理一些额外的过程才能结束,尤其是数据存储的模块,进程停止前为保证数据的完整性可能要做一些事情,如果发生段错误,这时就需要先截获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. }
时间: 2024-11-01 10:26:57

优雅处理段错误的相关文章

越界访问 段错误-急急急,用gdb调试程序出现段错误

问题描述 急急急,用gdb调试程序出现段错误 出错的函数如下: NodeTp*Crt(int n,char b[],char jj[]) { int i; NodeTp *p,*h,*last; CreateNode(h); last=h; for(i=0;i { if(jj[i]=='2') { CreateNode(p); if(b[i]=='1') { p->pf[0]=a[i][0]; p->pf[1]=a[i][1]; p->pf[2]=a[i][2]; p->SA=0;

用gdb配合内核转储文件瞬间定位段错误

前几天在写一个使用Huffman算法的文本压缩程序时被"段错误"折磨了好长时间.因为自己向来对内存的使用保持着"克勤克俭"的作风,所以总是被此类错误折磨的焦头难额.C语言的内存管理本来就是一个繁琐的工作,写代码时略有不慎便会出现诸如"段错误(吐核)"的运行时崩溃. 其实段错误是操作系统的一个内存保护机制,一般情况下某程序尝试访问其许可范围之外的内存空间时便会触发内核的"一般保护性异常",内核便会向程序发送一个SIGSEGV(1

关于c语言解析json,nalloc段错误问题

问题描述 关于c语言解析json,nalloc段错误问题 如图,我现在有四条数据,主函数传进来,前三条没问题, 第四条的时候段错误 gdb显示段错误位置在malloc,求助,为什么会这样 解决方案 1.有这种可能,你目前的修改方法只是降低了问题出现的概率. 2.建议你还是找出内存越界的原因,如果实在不想找,或者不好找,建议你先预估一下输入的数据最大有多大,然后申请足够的内存. 3.不过对于一个优秀的程序员,查找出问题的真正原因对你的进步是非常有帮助的. 解决方案二: C语言解析JSONJson解

多线程段错误-多线程挂掉----哪个大神可以解决下,多谢啦!

问题描述 多线程挂掉----哪个大神可以解决下,多谢啦! 1 #include 2 #include 3 #include 4 #include 5 #define PAI 3.14159 6 void* area(void* arg){ 7 double r = (double)arg; 8 double* s=malloc(sizeof(double)); 9 s = PAI * r * r; 10 return s; 11 } 12 int main(void) { 13 printf("

oracle 9.2.0.8 exp导出dmp导入报Segmentation fault/段错误故障解决

在9.2.0.8 rac环境中,使用exp导出来dmp文件任何报错(按单个表,按用户导出,使用tns方式远程exp导出),包括重启数据库后导出,无法导入到其他数据库中(本库,tns方式远程导入,ftp传输到远程导入,9i/10g/11g版本)报错类似有setillegal instruction(coredump),段错误,Segmentation fault等,以下列出来几个报错信息--导入11.2.0.2版本 Import: Release 11.2.0.2.0 - Production o

strcpy-将字符串常量附给三重数组的一个指针,出现段错误

问题描述 将字符串常量附给三重数组的一个指针,出现段错误 #include<stdio.h> #include<stdlib.h> #include<string.h> char*** Create3DActiveArray(int x, int y, int z) { char ***pArr; int i, j,k; pArr = (char ***)malloc(x * sizeof(char **)); for (i = 0; i < x; i++) {

linux-注释掉printf语句程序出现段错误

问题描述 注释掉printf语句程序出现段错误 最近在Linux下开发一个软件,为了调试方便加入了printf语句输出相关变量的值,开发完成后软件运行很正常,可当我把printf语句注释掉后再运行软件却总是出现segment fault,若把printf语句加上又能正常运行,按理说注释掉printf语句不应该会引起此类错误呀,搞得我一头雾水,还望大神们指点迷津 解决方案 可能你注释的时候没有注意括号和if语句 解决方案二: 这个不应该是printf引起的,看是不是注释了影响了代码的处理逻辑等 解

c语言-关于UBUNTU下C语言 段错误 转存储的问题

问题描述 关于UBUNTU下C语言 段错误 转存储的问题 在Linux下雪C语言编程时, 1.捕捉文件操作错误并打印错误信息:strerror(errno) 2.用域名取得ip地址是打印IP是调用:inet_ntoa()时 总是出现段错误 ,该如何解决! 解决方案 确认你定义了两个类似的结构体实例: struct sockaddr_in client socklen_t length; length=sizeof(client); 然后在accept()函数里面这样传递参数(注意传递地址) ac

测试-unix c中出现段错误,为什么

问题描述 unix c中出现段错误,为什么 单独测试 readins = jr_encoder(dest, 4, 2, 8, status.st_size, BLOCKSIZE);没问题,把这个列入单独的文件放在myJerasure.c中再调用就会出现上面的问题 解决方案 是不是分配空间太大了,具体要分析一下你的代码调用参数