在编写unix程序的时候,常常会出现一些错误,而最毁灭性的就是进程直接down掉
进程意外退出会给用户带来很多负面影响
同时如果调试和日志文件不够完善的话,查起错来相当麻烦,再加上用户环境和我们的开发环境不一样,当你回过头来改这个错误,如果日志不够完善,甚至需要在用户的环境下复现错误,这基本上是不可能的,尤其是你的代码要跑一段时间才能复现错误
我刚进公司的时候写了一些简单的应用程序,为快速实现功能同时由于缺少liunx环境下用户程序开发的经验,没有做好调试的工作,在开发环境下调试甚至是通过打印信息到终端来完成的,虽然最后在公司测试没什么问题,但是放到用户那里就会出错,而且还找不到原因,最后也搞不明白是自己程序的错误还是其他原因导致的
在吃了几次自己的亏以后,为每次都乖乖的把日志完善
下面总结以下进程会意外退出的几种情况
一.进程的退出
APUE 第7章第一页列出了8种进程退出的方式
其中5种是由我们的代码控制,通过调用退出的函数正常退出,这是我们程序中显示的退出,是容易查找也是容易控制的
另外3种退出是 异常退出,也是我们不愿看到,隐式的退出,分别是
1.调用abort
2.接收到一个信号并终止
3.最后一个线程对取消线程作出相应
对于abort,我们理解为人为制造异常让程序退出,其实就是制造SIGABRT信号给进程,进程不理会对这个信号的捕获忽略,捕获这个信号纯粹只是为了做一些清理工作,在信号处理函数中不做退出的话,信号处理函数返回时,进程会自己退出
第二种情况是我们最常见的意外退出的方式,待会仔细說
最后一种,在进程中的一个线程中错误调用exit(),_exit,_Exit,那么整个进程都会终止掉,或者最后一个线程的取消信号异步到来(信号处于未决状态),而取消并没有被设置为无效,那么线程就会被取消,整个进程也就消失了
二.导致进程意外退出的情况
导致意外退出的情况一般是两种
1.进程收到一个信号导致异常退出
2.你的代码有问题,运行异常导致退出(最常见的就是段错误,虽然也是一个信号)
首先分析信号:
1.信号从哪里来:进程自己产生或者操作系统内核发出
2.信号处理 :不同的信号采取不同的处理方法,有:
终止进程
终止进程并产生core dump文件
忽略信号
暂停程序
重新调度(取消暂停)
实际上我们要处理的主要是前两种情况
处理信号:
信号会终止进程是因为当进程收到信号如果我们不捕获这个信号,大多数的信号采取的默认操作都是终止进程,除非我们捕获这个信号执行用户自定义的处理函数
如果我们能正确捕捉信号而且明确这个信号不会对我们的系统造成影响,将这个信号忽略掉,那么就减少了我们程序意外终止的几率
下面简单说說编写代码的错误
这类错误其实是不难被发现的,因为这类错误导致的结果应该是比较显式的
比如说除法运算错误的除数
比如說段错误,在测试阶段不难被发现
线程中调用exit()来退出线程
还有就是内存泄漏带来的问题也是比较明显的
进程中错误的休眠
三.避免进程意外退出
1.一般来说我们是无需处理信号,信号作为进程间通信的一种手段,自然是有它的作用
2.确保编程中不要出现非法的操作
3.对一些信号捕获和忽略 常见的比如 SIGPIPE
4.最好退出前做一些清理工作保证就算意外退出也不会对系统造成影响,比如释放内存,删除临时文件
四.问题
进程退出大多是由于信号的关系,而哪些信号该捕获忽略,那些信号不能忽略是个头疼的问题,另外进程的退出也可能会是一些看似正常的退出,比如代码中的系统调用被信号中断错误的返回一个错误号,而不加分析的将进程退出也是我们不愿看到的
五.做好调试与定位
好了,回到我们一开始提出的问题就是认真将每一个可能的出错都记录到日志文件中,这样我们在出错的时候也不至于一点头绪都没有,
还有就是使用GDB调试也是定位错误的好方法