当我们想强制结束一个程序的时候,我们通常会给它发送一个信号然后该进程捕捉到信号,再然后该进程执行一定操作最终被终止。信号是UNIX和Linux系统响应某些条件而产生的一个事件,接收到该信号的进程会相应地采取一些行动。通常信号是由一个错误产生的。但它们还可以作为进程间通信或修改行为的一种方式,明确地由一个进程发送给另一个进程。

一个信号的产生叫生成,接收到一个信号叫捕获,生成信号的主要函数有:kill()、raise()、 sigqueue()、alarm()、setitimer()以及abort(),最常用的是kill;捕获信号的主要函数有:signal(),sigprocmask() ,sigpending(),sigsuspend(), sigemptyset(),最常用的是signal。下面重点讲一下kill和signal的使用。

1.信号的生成kill

在Linux系统下想结束某个进程时,用的最多的指令就是kill或者killall,这就是常用的信号生成方式,在程序运行时ctrl+c中断进程,会产生信号SIGINT。在Linux系统对应kill命令也有kill函数,c语言引入头文件sys/types.h和signal.h之后就可以使用。kill 送出一个特定的信号 (signal) 给行程 id 为 pid 的行程根据该信号而做特定的动作,若没有指定,预设是送出终止 (SIGTERM) 的信号,例如kill -9 pid就是强制杀死进程号为pid的进程。在这里有人就会问为什么要用-9呢,-9只是kill发送信号的一个编号,可以输入kill –l把kill所有可用的信号名称列出来。

kill -9 意思是把SIGKILL信号发送给进程号为pid的进程。

其中前面31个信号为不可靠信号(非实时的,可能会出现信号的丢失),后面的信号为可靠信号(实时的real_time,对信号排队,不会丢失)。

1) SIGHUP (挂起) 当运行进程的用户注销时通知该进程,使进程终止

2) SIGINT (中断) 当用户按下时,通知前台进程组终止进程

3) SIGQUIT (退出) 用户按下或时通知进程,使进程终止

4) SIGILL (非法指令) 执行了非法指令,如可执行文件本身出现错误、试图执行数据段、堆栈溢出

5) SIGTRAP 由断点指令或其它trap指令产生. 由debugger使用

6) SIGABRT (异常中止) 调用abort函数生成的信号

7) SIGBUS 非法地址, 包括内存地址对齐(alignment)出错. eg: 访问一个四个字长的整数, 但其地址不是4的倍数.

8) SIGFPE (算术异常) 发生致命算术运算错误,包括浮点运算错误、溢出及除数为0.

9) SIGKILL (确认杀死) 当用户通过kill -9命令向进程发送信号时,可靠的终止进程

10) SIGUSR1 用户使用

11) SIGSEGV (段越界) 当进程尝试访问不属于自己的内存空间导致内存错误时,终止进程

12) SIGUSR2 用户使用

13) SIGPIPE 写至无读进程的管道, 或者Socket通信SOCT_STREAM的读进程已经终止,而再写入。

14) SIGALRM (超时) alarm函数使用该信号,时钟定时器超时响应

15) SIGTERM (软中断) 使用不带参数的kill命令时终止进程

17) SIGCHLD (子进程结束) 当子进程终止时通知父进程

18) SIGCONT (暂停进程继续) 让一个停止(stopped)的进程继续执行. 本信号不能被阻塞.

19) SIGSTOP (停止) 作业控制信号,暂停停止(stopped)进程的执行. 本信号不能被阻塞, 处理或忽略.

20) SIGTSTP (暂停/停止) 交互式停止信号, Ctrl-Z 发出这个信号

21) SIGTTIN 当后台作业要从用户终端读数据时, 终端驱动程序产生SIGTTIN信号

22) SIGTTOU 当后台作业要往用户终端写数据时, 终端驱动程序产生SIGTTOU信号

23) SIGURG 有"紧急"数据或网络上带外数据到达socket时产生.

24) SIGXCPU 超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/改变。

25) SIGXFSZ 当进程企图扩大文件以至于超过文件大小资源限制。

26) SIGVTALRM 虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间.

27) SIGPROF (梗概时间超时) setitimer(2)函数设置的梗概统计间隔计时器(profiling interval timer)

28) SIGWINCH 窗口大小改变时发出.

29) SIGIO(异步I/O) 文件描述符准备就绪, 可以开始进行输入/输出操作.

30) SIGPWR 电源失效/重启动

31) SIGSYS 非法的系统调用。

程序不可捕获、阻塞或忽略的信号有:SIGKILL,SIGSTOP。
不能恢复至默认动作的信号有:SIGILL,SIGTRAP。
默认会导致进程退出的信号有:SIGALRM,SIGHUP,SIGINT,SIGKILL,SIGPIPE,SIGPOLL,SIGPROF,SIGSYS,SIGTERM,SIGUSR1,SIGUSR2,SIGVTALRM。
默认会导致进程停止的信号有:SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU。
默认进程忽略的信号有:SIGCHLD,SIGPWR,SIGURG,SIGWINCH。

2.信号的捕获signal

signal的函数原型是:

        typedef void (*sig_t)( int );

        sig_t signal(int signum,sig_t handler);

第一个参数signum指明了所要处理的信号类型,它可以取除了SIGKILL和SIGSTOP外的任何一种信号。

第二个参数handler描述了与信号关联的动作,它可以取以下三种值:

(1)一个无返回值的函数地址

此函数必须在signal()被调用前申明,handler中为这个函数的名字。当接收到一个类型为signum的信号时,就执行handler 所指定的函数。这个函数应有如下形式的定义:

void func(int sig);

(2)SIG_IGN

这个符号表示忽略该信号,执行了相应的signal()调用后,进程会忽略类型为sig的信号。

(3)SIG_DFL

这个符号表示恢复系统对信号的默认处理。

最常用的捕获signal场景是当signal到来时,程序运行某函数,函数由你自己指定,此时函数一般是做一些资源的释放,比如socket关闭,内存释放,文件关闭,有人会说了我不释放那些资源也可以退出程序,你说的没错,你不做任何处理一样可以退出程序,但是有时会影响其他共享或者交互进程,比如作为服务端异常退出时不主动关闭socket,可能会导致客户端不知道断开连接,导致某些数据丢失或者逻辑异常,所以在程序正常和异常退出时最好都做到优雅,这里除了SIGKILL,SIGSTOP除外,因为这些信号无法捕获想优雅退出不给机会。

代码示例:

#include <stdio.h>

#include <signal.h>

void server_uninit()

{

//释放所有资源

        printf("close all socket and file\n");

}

void func1()

{

        printf("SIGINT \n");

server_uninit();

        printf("可以优雅的退出程序了 \n");

        exit(0);

}

void func2()

{

        printf("SIGTERM \n");

server_uninit();

        printf("可以优雅的退出程序了 \n");

        exit(0);

}

void func3()

{

        printf("SIGSEGV \n");

server_uninit();

        printf("可以优雅的退出程序了 \n");

        exit(0);

}

void func0()

{

        printf("SIGKILL \n");

server_uninit();

        printf("可以优雅的退出程序了 \n");

        exit(0);

}

int main()

{

        signal (SIGINT, func1);

        signal(SIGKILL, func0);

        signal(SIGSEGV, func3);

        signal(SIGTERM, func2);

        int i = 0;

        while(1)

{

                printf("i %d\n",i++);

sleep(2);

}

        return 0;

}

Linux系统下程序异常如何优雅的退出相关推荐

  1. 如何查看Linux系统下程序运行时使用的库?

    Linux系统下程序运行会实时的用到相关动态库,某些场景下,比如需要裁剪不必要的动态库时,就需要查看哪些动态库被用到了. 以运行VLC为例. VLC开始运行后,首先查看vlc的PID,比如这次查到的V ...

  2. linux wordpress伪静态,wordpress程序在win和Linux系统下的伪静态设置 - 张力博客

    这是一篇很早就应该写的文章,而在昨天就有朋友问我,为什么不写一下关于wordpress的伪静态设置呢?今天这篇文章我就来跟大家说一下,关于wordpress程序在win和Linux系统下的伪静态设置方 ...

  3. Linux系统下强制关闭程序

    Linux系统下强制关闭程序 kill -9 `ps -ef|grep program_name|awk '{print $2}'` 杀掉名称中有program_name的进程 awk '{print ...

  4. node.js命令行程序在Windows系统和Linux系统下的部署

    在Windows系统下全局部署node.js写的命令行程序 我们有一个简单的命令行程序,使用node.js的commander模块写的,只有一个文件hello.js,其内容如下: #!/usr/bin ...

  5. linux daemon步骤,编写Linux系统下Daemon程序的方法步骤

    编写Linux系统下Daemon程序的方法步骤 一.引言 Daemon程序是一直运行的服务端程序,又称为守护进程. 本文介绍了在Linux下编写Daemon程序的步骤,并给出了例子程序. 二.Daem ...

  6. linux系统下Qt应用程序重启,嵌入式Linux重启QT应用程序的简单办法(基于QT4.8 qws)...

    嵌入式Linux重启QT应用程序的简单办法(基于QT4.8 qws) 应用软件一般都有这样的业务需求: 当有新版本的APP,则程序就需要执行更新,更新完毕后(所谓的更新大多就是以覆盖的方式),不需要关 ...

  7. 【操作系统】如何在linux系统下运行C程序

    如何在linux系统下运行C程序 linux系统与windows系统不同,如何在linux中运行C,我们来看看吧. 工具/原料 Linux虚拟机 电脑 方法/步骤 查看全文 http://www.ta ...

  8. 在linux系统下如何编译运行C语言程序和C++程序

    文章目录 1:linux系统下编译运行C程序 2:linux系统下编译C++程序 1:linux系统下编译运行C程序 gcc -o a a.c gcc -o 想要的文件名 文件的名字.c 2:linu ...

  9. 在linux操作系统中启动oracle数据库程序,Linux系统下Oracle数据库的安装和启动关闭操作教程...

    这篇文章主要介绍了Linux系统下Oracle数据库的安装和启动关闭操作教程,并针对在sqlplus下所需执行的命令进行讲解,需要的朋友可以参考下 1.准备: df -H 查看空间剩余   一般准备最 ...

最新文章

  1. [Win]进程间通信——邮槽Mailslot
  2. 【编码】-小Ho的防护盾-2016.08.14
  3. java 特殊符号正则_java利用正则表达式处理特殊字符的方法实例
  4. struts2学习笔记二--准备struts2的学习和开发环境
  5. vue中的uri_浅谈vue-resource和vue-axios的区别
  6. request对象作为:作用域
  7. 概念理解之装箱与拆箱
  8. 说一说javascript跨域和jsonp
  9. java jxls_java使用jxls导出Excel
  10. 从浏览器中获取headers
  11. 在哪里能看到计算机缓存大小,怎么查看电脑硬盘缓存大小
  12. JS,统计图表大全--十一、甘特图
  13. 《按自己的意愿过一生》语录一
  14. pv是什么意思?增长方法有哪些!
  15. 宝塔Linux面板登录的账号密码忘了怎么办?
  16. 计算机组成原理大题速成,计算机组成原理大题
  17. Go语言处理Windows系统的图标ICO文件(下)
  18. 考研逻辑整理 - 负判断、联言判断和联言推理
  19. latex参考文献太长,换行处理
  20. 对于DFA、NFA理解

热门文章

  1. 腾讯应用中的轩辕诀这款游戏好玩不?轩辕诀游戏介绍
  2. 【前端开发环境安装、配置、项目搭建全教程】
  3. 网络安全-信息收集- 谷歌浏览器插件收集信息,谷歌hacking搜索语法-带你玩不一样的搜索引擎
  4. gin集成支付宝支付
  5. VS 可替换弱符号 转自stackflow(没试验过)
  6. 视频行为识别检测综述 IDT TSN CNN-LSTM C3D CDC R-C3D
  7. 一文带你了解React框架
  8. 2019数据科学/人工智能比赛作品解决方案合集
  9. reduce()使用场景、用法总结
  10. kotlin - 线程 Thread