程序遇到core的时候 使得程序继续执行的解决办法
2013-11-20 15:37
288 查看
最近有点懒了,好久没有更新博客了,今天来一发。
在代码开发过程中,我们经常会遇到程序core掉,这个时候正常的处理步骤是,我们保留程序的coredump,然后分析,进而找出程序的bug,fix it!
但是,如果你的程序是线上服务,而且只会有极少数的输入会导致程序core掉,而且你允许可以有少量错误发生,那么这时候,我们的一个直观想法是,有没有什么方法可以 跳过这些该死的极少数异常数据,使得程序继续执行?
特别是在用c++开发基于streaming的hadoop程序时,如果我们的代码里有一些很难找到的bug,这些bug对于特定的输入会导致程序core掉,从而导致整个hadoop job失败(如果你没有使用-D mapred.max.map.failures.percent 来设置hadoop job的失败率),是一个让人极度郁闷的事。(虽然是我们自己的bug...)
那么,到底有没有什么办法使得我们在遇到core的时候,返回到程序的某一个正确的位置,从而继续执行我们的程序呢?
linux c下面提供了一套API,用于实现函数之间的跳转,函数原型如下:
函数longjmp()通过把堆栈复位成envbuf中描述的状态进行操作(envbuf的设置是由预先调用setjmp()生成的),这样使程序重新从setjmp()调用后的下一个语句开始运行,使计算机认为从刚刚执行完setjmp()的函数。从效果上看,longjmp()函数似乎“绕”过了时间和空间(内存)回到程序的原点,不必执行正常的函数返回过程。
运用这种机制,我们就可以跳过可能会造成程序core掉的坏数据,使得程序继续运行。
1、首先,我们要使用setjmp设置从哪里重新开始运行我们的程序
2、然后,我们要设置段错误的信号捕捉函数
3、最后,在信号处理函数中使用longjmp调回到我们使用setjmp设置的位置,继续执行程序。
下面给出一段示例代码
在代码开发过程中,我们经常会遇到程序core掉,这个时候正常的处理步骤是,我们保留程序的coredump,然后分析,进而找出程序的bug,fix it!
但是,如果你的程序是线上服务,而且只会有极少数的输入会导致程序core掉,而且你允许可以有少量错误发生,那么这时候,我们的一个直观想法是,有没有什么方法可以 跳过这些该死的极少数异常数据,使得程序继续执行?
特别是在用c++开发基于streaming的hadoop程序时,如果我们的代码里有一些很难找到的bug,这些bug对于特定的输入会导致程序core掉,从而导致整个hadoop job失败(如果你没有使用-D mapred.max.map.failures.percent 来设置hadoop job的失败率),是一个让人极度郁闷的事。(虽然是我们自己的bug...)
那么,到底有没有什么办法使得我们在遇到core的时候,返回到程序的某一个正确的位置,从而继续执行我们的程序呢?
linux c下面提供了一套API,用于实现函数之间的跳转,函数原型如下:
头文件:#include <setjmp.h> 函数原型: int setjmp(jmp_buf env); void longjmp(jmp_buf env, int val); int sigsetjmp(sigjmp_buf env, int savesigs); void siglongjmp(sigjmp_buf env, int val); setjmp函数用于设置跳转的目的位置,longjmp函数进行跳转。 env:保留了需要返回的位置的堆栈情况。 savesigs:是否保存信号 setjmp的返回值:直接调用该函数,则返回0;若由longjmp的调用,导致setjmp被调用,则返回val(longjmp的第二个参数)。 在Linux中使用longjmp有一个问题,当捕捉到一个信号的时候进入信号处理函数,此时当前信号自动加入到进程的信号屏蔽字中,这就阻止了后来的这种信号中断该信号处理程序。如果用longjmp跳出信号处理程序,那么该进程的信号屏蔽字不会被恢复到调用信号处理程序前的信号屏蔽字。如果想恢复的话,就要使用sigsetjmp和siglongjmp函数。
函数longjmp()通过把堆栈复位成envbuf中描述的状态进行操作(envbuf的设置是由预先调用setjmp()生成的),这样使程序重新从setjmp()调用后的下一个语句开始运行,使计算机认为从刚刚执行完setjmp()的函数。从效果上看,longjmp()函数似乎“绕”过了时间和空间(内存)回到程序的原点,不必执行正常的函数返回过程。
运用这种机制,我们就可以跳过可能会造成程序core掉的坏数据,使得程序继续运行。
1、首先,我们要使用setjmp设置从哪里重新开始运行我们的程序
2、然后,我们要设置段错误的信号捕捉函数
3、最后,在信号处理函数中使用longjmp调回到我们使用setjmp设置的位置,继续执行程序。
下面给出一段示例代码
#include <iostream> #include <signal.h> #include <setjmp.h> #include <string> #include <sys/types.h> #include <unistd.h> using namespace std; jmp_buf ebuf;//初始化堆栈 //段错误的信号处理函数 void OnSIGSEGV(int signum, siginfo_t *info, void *ptr) { cout << "occur bad input\n"; // 跳转到setjmp设置的位置,继续执行程序 siglongjmp(ebuf,1); } //一个模拟会导致段错误的函数 void func_may_cause_core(const string &line) { if(line == "a") { //send a SIGSEGV signal pid_t pid = getpid(); kill(pid, SIGSEGV); } } int main() { //设置信号捕捉函数 struct sigaction act; int sig = SIGSEGV; sigemptyset(&act.sa_mask); act.sa_sigaction = OnSIGSEGV; act.sa_flags = SA_SIGINFO; if(sigaction(sig, &act, NULL)<0) { perror("sigaction:"); } //设置程序重新开始执行的位置 sigsetjmp(ebuf); string line; while(getline(cin, line)) { func_may_cause_core(line); cout << "good input " << line << endl; } return 0; } 输出: b good input b c good input c d good input d a occur bad input e good input e a occur bad input f good input f
相关文章推荐
- 在编译安装程序时候遇到/usr/bin/ld: cannot find -lxxx的时候的解决办法。
- Spark程序执行过程中遇到的线程安全问题及解决办法
- windows环境下Eclipse开发MapReduce程序遇到的四个问题及解决办法
- Linux下SSH远程连接断开后让程序继续运行解决办法
- 在 root 下执行 Oracle 程序时找不到 libclntsh.so.11.1 错误的解决办法。
- “对不起,您安装的不是正版应用,安装程序无法继续执行 discuz”解决方法
- ios升级为5后,程序编译时遇到的关于libz 1.2.3.dylib类包的各种问题解决办法
- 关于执行Oracle下Sql语句中遇到的特殊字符问题解决办法。
- 记录编译vnc-4_1_3-unixsrc的时候遇到的问题与解决办法
- ArcGIS API for Flex制作程序发布后出现错误:"访问 URL 时遇到安全性错误" 解决办法尝试(学习笔记)
- 运行VS可执行文件 360提示有菠萝影音插件想要捆绑 导致程序无法正常编译和运行解决办法
- 使用Hibernate 5.0、4.0、3.0 createSQLQuery执行原生Sql语句 遇到问题及解决办法集锦
- QT下生成可执行程序的方法及一些问题解决办法:
- scrapy爬虫中编写代码的时候遇到Error13的解决办法
- 小程序onLaunch异步,首页onLoad却先执行的解决办法
- 安装SQL时遇到:安装程序配置服务器失败的解决办法
- 在 root 下执行 Oracle 程序时找不到 libclntsh.so.11.1 错误的解决办法。
- git add . 的时候遇到warning: LF will be replaced by CRLF in ...... 解决办法
- Linux下执行程序出现 Text file busy 时的解决办法
- 自定义SiteMap后,SiteMap.SiteMapResolve事件处理程序不执行解决办法