Linux 信号

来源:互联网 发布:mac pretty boy 编辑:程序博客网 时间:2024/05/29 19:20


   Linux中的一个重要概念——信号。 信号与进程的状态转换息息相关。


信号的基本概念

   信号属于Linux的低级通信,主要用于在进程间传递控制信号。
   在Linux系统中,信号是在软件层次上对中断机制的一种模拟。一个进程接收到信号之后,有相应的信号的处理程序,而一个进程也可以给另外一个(或一组)进程发送信号。在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。
    使用信号进行进程间通信(IPC)是UNIX系统中的一种传统机制,Linux也支持这种机制。在Linux中,异步通知使用信号来实现。

    软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。进程之间可以互相通过系统调用 kill 发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。注意,信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据。
    信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号什么时候到达。
    异步通知的意思是:一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似硬件上“中断”的概念。
    
进程对信号的响应:
    通常发生在两种情况下:1、当进程由于系统调用、中断或异常而进入核心态,从核心态返回用户态之前;2、当前进程在核心态中由睡眠刚被唤醒的时候,由于信号的存在而提前返回到用户空间中。
             

进程对信号的处理方法:
    收到信号的进程对各种信号有不同的处理方法。处理方法可以分为三类:
          第一种方法是,类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数, 由该函数来处理
          第二种方法是,忽略某个信号,对该信号不做任何处理,就象未发生过一样
          第三种方法是,对该信号的处理保留系统的默认值,这种缺省操作, 对大部分的信号的缺省操作是使得进程终止。进程通过系统调用 signal 来指定进程对某个信号的处理行为。

    在进程表的表项中有一个软中断信号域,该域中每一位对应一个信号,当有信号发送给进程时,对应位置位。由此可以看出,进程对不同的信号可以同时保留, 但对于同一个信号,进程并不知道在处理之前来过多少个。

实例:
    为了理解信号,先从我们最熟悉的场景说起:
   (1)用户输入命令,在shell下启动一个前台进程;
   (2)用户按 Ctrl+c 快捷键,这个键盘输入产生一个硬件中断。
   (3)如果CPU正在执行这个进程的代码,则该进程的用户空间代码暂停执行CPU从用户态切换到内核态处理硬件中断。
   (4)终端驱动程序将 Ctrl+c 解释成一个 SIGINT 信号,记在该进程的 PCB 中(也可以说发送了一个SIGINT信号给该进程)。
   (5)当某个时刻要从内核空间返回该进程的用户空信号间代码继续执行之前首先处理PCB中的记录信号,发现有一个SIGINT信号待处理,这个信号的默认动作是终止进程,所以直接终止进程,而不在返回到它的用户空间代码执行。
 
   注意:   shell 可以同时运行一个前台进程和任意多个后台进程,只有前台进程才能接收到像 Ctrl+c 这种控制键产生的信号。 用户可以随时按下 Ctrl+c 向前台正在执行用户空间代码进程发送相应的信号,而进程也能收到该信号,所以:信号相对于进程的控制流程来说是异步(Asynchronous)的。
  

Linux 系统支持的信号通过 kill -l 命令查看

  1. [root@web1 ~]# kill -l
  2. 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
  3. 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
  4. 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
  5. 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
  6. 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
  7. 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
  8. 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
  9. 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
  10. 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
  11. 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
  12. 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
  13. 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
  14. 63) SIGRTMAX-1 64) SIGRTMAX
 
   每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到,编号34以上的是实时信号,不对它进行讨论,看一下34以下的信号:
  1. 名字 | 默认操作 | 描述
  2. -------------------------------------
  3. SIGHUP 终止进程 终端线路挂断
  4. SIGINT 终止进程 中断进程
  5. SIGQUIT 建立CORE文件终止进程,并且生成core文件 | 退出程序
  6. SIGILL 建立CORE文件 非法指令
  7. SIGTRAP 建立CORE文件 跟踪自陷
  8. SIGBUS 建立CORE文件 总线错误
  9. SIGSEGV 建立CORE文件 段非法错误
  10. SIGFPE 建立CORE文件 浮点异常
  11. SIGIOT 建立CORE文件 执行I/O自陷
  12. SIGKILL 终止进程 杀死进程
  13. SIGPIPE 终止进程 向一个没有读进程的管道写数据
  14. SIGALARM 终止进程 计时器到时
  15. SIGTERM 终止进程 软件终止信号
  16. SIGSTOP 停止进程 非终端来的停止信号
  17. SIGTSTP 停止进程 终端来的停止信号
  18. SIGCONT 忽略信号 继续执行一个停止的进程
  19. SIGURG 忽略信号 I/O紧急信号
  20. SIGIO 忽略信号 描述符上可以进行I/O
  21. SIGCHLD 忽略信号 当子进程停止或退出时通知父进程
  22. SIGTTOU 停止进程 后台进程写终端
  23. SIGTTIN 停止进程 后台进程读终端
  24. SIGXGPU 终止进程 CPU时限超时
  25. SIGXFSZ 终止进程 文件长度过长
  26. SIGWINCH 忽略信号 窗口大小发生变化
  27. SIGPROF 终止进程 统计分布图用计时器到时
  28. SIGUSR1 终止进程 用户定义信号1
  29. SIGUSR2 终止进程 用户定义信号2
  30. SIGVTALRM 终止进程 虚拟计时器到时

 1) SIGHUP 本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联.
2) SIGINT 程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl+C)时发出
3) SIGQUIT 和SIGINT类似, 但由QUIT字符(通常是Ctrl+\)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号.
4) SIGILL 执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生这个信号.
5) SIGTRAP 由断点指令或其它trap指令产生. 由debugger使用.
6) SIGABRT 程序自己发现错误并调用abort时产生.
6) SIGIOT 在PDP-11上由iot指令产生, 在其它机器上和SIGABRT一样.
7) SIGBUS 非法地址, 包括内存地址对齐(alignment)出错. eg: 访问一个四个字长的整数, 但其地址不是4的倍数.
8) SIGFPE 在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误.
9) SIGKILL 用来立即结束程序的运行. 本信号不能被阻塞, 处理和忽略.
10) SIGUSR1 留给用户使用
11) SIGSEGV 试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据.
12) SIGUSR2 留给用户使用
13) SIGPIPE Broken pipe
14) SIGALRM 时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号.
15) SIGTERM 程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理. 通常用来要求程序自己正常退出. shell命令kill缺省产生这个信号.
17) SIGCHLD 子进程结束时, 父进程会收到这个信号.
18) SIGCONT 让一个停止(stopped)的进程继续执行. 本信号不能被阻塞. 可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作. 例如, 重新显示提示符
19) SIGSTOP 停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略.
20) SIGTSTP 停止进程的运行, 但该信号可以被处理和忽略. 用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号
21) SIGTTIN 当后台作业要从用户终端读数据时, 该作业中的所有进程会收到SIGTTIN信号. 缺省时这些进程会停止执行.
22) SIGTTOU 类似于SIGTTIN, 但在写终端(或修改终端模式)时收到.
23) SIGURG 有"紧急"数据或out-of-band数据到达socket时产生.
24) SIGXCPU 超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/改变
25) SIGXFSZ 超过文件大小资源限制.
26) SIGVTALRM 虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间.
27) SIGPROF 类似于SIGALRM/SIGVTALRM, 但包括该进程用的CPU时间以及系统调用的时间.
28) SIGWINCH 窗口大小改变时发出.
29) SIGIO 文件描述符准备就绪, 可以开始进行输入/输出操作.
30) SIGPWR Power failure
   
Linux系统产生信号的条件主要有:

(1)用户在终端按下某些键时,终端驱动程序会发送信号给前台进程。
(2)硬件异常产生信号,这些条件由硬件检测到并通知内核,然后由内核向前台进程发送适当的信号。
(3)一个进程调用 kill 函数,可以发送信号给另一个进程。
(4)可以用kill命令发送系统支持的信号给某个进程,kill命令也是调用kill函数实现的,如果不指明信号,则默认发送 SIGTERM 信号,该信号的处理动作是终止进程。(命令:kill PID号就是这种机制)
(5)当内核检测到某种软件条件发生时,也可用过信号通知进程。例如闹钟超时时产生 SIGALRM 信号;向读端已关闭的管道写数据时产生 SIGPIPE 信号、。

  总结: Linux系统中运行的进程可以接收信号,默认情况下会有相应的行为与信号对应。进程能够忽略和捕获除了SIGSTOP和SIGKILL这两个信号以外的所有其他信号。一个信号被捕获的意思是当一个信号到达时有相应的代码处理它。如果一个信号没有被这个进程所捕获,内核将采用默认行为处理。

Linux系统产生信号
   Linux系统中产生信号,向某个特进程发送信号一般有两种方法:

(1) 通过终端按键产生信号:(只对前台进程有效)
      Ctrl+C     SIGINT   终止进程
       Ctrl+z     SIGTSTP   停止进程的运行
       Ctrl+\    SIGQUIT   终止信号 
(2)通过系统调用产生信号
  
   通过 shell 工具: kill。
   kill 命令被设计用来向指定的进程发送信号。(看起来像是杀死进程的命令) 它可以向任何进程发送任何信号,只要权限够!
 
  1.  The  command  kill  sends the specified signal to the specified process or process group.  If no signal is specified, the TERM signal is sent.  The TERM signal  will kill  processes  which  do  not catch this signal.For other processes, it may be  necessary to use the KILL (9) signal, since this signal cannot be caught.
  kill -signal pid号

  1. [root@web1 ~]# jobs -l
  2. [1]- 24480 Running sleep 10001 &
  3. [3]+ 24482 Running sleep 10003 &
  4. [root@web1 ~]# kill -SIGQUIT 24482 // 向进程发送信号SIGQUIT,进程收到信号,会执行相应的函数退出
  5. [root@web1 ~]# jobs -l
  6. [1]- 24480 Running sleep 10001 &
  7. [3]+ 24482 退出 sleep 10003 // 瞬时状态
  8. [root@web1 ~]# jobs -l
  9. [1]+ 24480 Running sleep 10001 & // 已经退出
  10. [root@web1 ~]# kill -SIGTSTP 24480 // 停止信号,被挂起
  11. [1]+ Stopped sleep 10001
  12. [root@web1 ~]# jobs -l
  13. [1]+ 24480 停止 sleep 10001
  14. [root@web1 ~]# kill -9 24480 // 信号 9 与 信号 SIGKILL 对应,强制杀死进程 [root@web1 ~]# jobs -l[1]+ 24480 已杀死 sleep 10001



总结: 系统可以使用信号来操纵进程,进程可以捕获大部分信号。根据进程的实现,它可以选择忽略,或者响应期待的操作。但是有两个信号,进程无法捕捉,他们是 kill 和 STOP。这两个信号可以立即杀死或暂停进程,而被杀死或暂停的进程无法忽略它。
  发送信号可以使用 kill 命令。



参考:《Shell编程从入门到精通》张昊

http://blog.csdn.net/yanlinwang/article/details/8197468
http://blog.csdn.net/hen_man/article/details/7288684


0 0
原创粉丝点击