信号(signal)

Posted Shemesz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了信号(signal)相关的知识,希望对你有一定的参考价值。

一、signal的介绍

  软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。在软件层次上是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是进程间通信机制中唯一的异步通信机制,一个进程不必通过任何操作来等待信号的到来,事实上,进程也不知道信号到底什么时候到达。进程之间可以互相通过系统调用kill()发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件信号除了基本通知的功能外,还可以传递附加信息。收到信号的进程对各种信号有不同的处理方法。处理方法可以分成三类:

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

二、信号的分类

· 可靠信号与不可靠信号

   Linux信号机制基本上是从Unix系统中继承过来的。早期Unix系统中的信号机制比较简单和原始,信号值小于SIGRTMIN的信号都是不可靠信号。这就是"不可靠信号"的来源,它的主要问题是信号可能丢失。随着时间的发展,实践证明了有必要对信号的原始机制加以改进和扩充。由于原来定义的信号已有许多应用,不好再做改动,最终只好又新增加了一些信号,并在一开始就把它们定义为可靠信号,这些信号支持排队,不会丢失。我们可以使用 kill -l 命令查看当前系统支持的信号,需要注意的是不同的系统支持的信号是不一样的:
在这里插入图片描述
   信号值位于SIGRTMIN和SIGRTMAX之间的信号都是可靠信号,可靠信号克服了信号可能丢失的问题。对于目前linux的两个信号安装函数:signal()及sigaction()来说,它们都不能把SIGRTMIN以前的信号变成可靠信号(都不支持排队,仍有可能丢失,仍然是不可靠信号),而且对SIGRTMIN以后的信号都支持排队。这两个函数的最大区别在于,经过sigaction安装的信号都能传递信息给信号处理函数,而经过signal安装的信号不能向信号处理函数传递信息。对于信号发送函数来说也是一样的。

· 实时信号和非实时信号

  早期Unix系统只定义了32种信号,前32种信号已经有了预定义值,每个信号有了确定的用途及含义,并且每种信号都有各自的缺省动作。如按键盘的CTRL ^C时,会产生SIGINT信号,对该信号的默认反应就是进程终止。后32个信号表示实时信号,等同于前面阐述的可靠信号。这保证了发送的多个实时信号都被接收。

  非实时信号都不支持排队,都是不可靠信号;实时信号都支持排队,都是可靠信号。

  通过上文的了解,可以知道 kill -l 命令可以查看信号种类,下面我们就了解一下常用信号的作用

信号编号信号名信号说明默认动作
2SIGINTCtrl+C按键终止程序运行的信号程序终止
4SIGILL非法的指令程序终止
7SIGBUS运行非本CPU相关编译器编译的程序程序终止
9SIGKILL强制杀死程序信号,任何程序都不可以捕捉该信号 程序终止,不可被捕捉
10SIGUSR1用户自定义信号1程序终止
11SIGSEGV段错误系统给程序发送的信号程序终止
12SIGUSR2用户自定义信号2程序终止
13SIGPIPE管道破裂信号程序终止
14SIGALRMalarm()系统调用发送的信号程序终止
15SIGTERMkill命令默认发送的信号,默认动作是终止信号程序终止
17SIGCHLD子进程退出信号忽略该信号

三、安装信号

(1)函数原型

信号的使用最好的方式还是: 查看man手册
Linux下有signal()和sigaction()两种信号安装的函数, 其中signal()函数的原型如下:

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
  • 第一个参数指定信号的值,
  • 第二个参数指定针对前面信号值的处理,可以忽略该信号(参数设为SIG_IGN);可以采用系统默认方式处理信号(参数设为SIG_DFL);也可以自己实现处理方式(参数指定一个函数地址)。

如果signal()调用成功,返回最后一次为安装信号signum而调用signal()时的handler值;失败则返回SIG_ERR。传递给信号处理例程的整数参数是信号值,这样可以使得一个信号处理例程处理多个信号。

(2)程序示例

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <unistd.h>
 4 #include <signal.h>
 5 #include <stdlib.h>
 6 #include <execinfo.h>
 7
 8 int g_sigstop = 0;
 9
10 void signal_stop(int signum)
11 {
12 if( SIGTERM == signum )
13 {
14 printf("SIGTERM signal detected\\n");
15 }
16 else if( SIGALRM == signum )
17 {
18 printf("SIGALRM signal detected\\n");
19 g_sigstop = 1;
20 }
21 }
22
23 void signal_user(int signum)
24 {
25 if(SIGUSR1 == signum)
26 {
27 printf("SIGUSR1 signal detected\\n");
28 }
29 else if(SIGUSR2 == signum)
30 {
31 printf("SIGUSR2 signal detected\\n");
32 }
33
34 g_sigstop = 1;
35 }
36
37 void signal_code(int signum)
38 {
39 if(SIGBUS == signum)
40 {
41 printf("SIGBUS signal detected\\n");
42 }
43 else if(SIGILL == signum)
44 {
45 printf("SIGILL signal detected\\n");
46 }
47 else if(SIGSEGV == signum)
48 {
49 printf("SIGSEGV signal detected\\n");
50 }
51
52 exit(-1);
53 }
54
55 int main(int argc, char **argv)
56 {
57 char *ptr=NULL;
58 struct sigaction sigact, sigign;
59 
60 /*+--------------------------------------+
61 *| Method1: Use signal() install signal |
62 *+--------------------------------------+*/
63 
64 signal(SIGTERM, signal_stop);
65 signal(SIGALRM, signal_stop);
66 
67 signal(SIGBUS, signal_code);
68 signal(SIGILL, signal_code);
69 signal(SIGSEGV, signal_code);
70 
71 /*+-----------------------------------------+
72 *| Method2: Use sigaction() install signal |
73 *+-----------------------------------------+*/
74 
75 /* Initialize the catch signal structure. */
76 sigemptyset(&sigact.sa_mask);
77 sigact.sa_flags = 0;
78 sigact.sa_handler = signal_user;
79 
80 /* Setup the ignore signal. */
81 sigemptyset(&sigign.sa_mask);
82 sigign.sa_flags = 0;
83 sigign.sa_handler = SIG_IGN;
84 
85 sigaction(SIGINT, &sigign, 0); /* ignore SIGINT signal by CTRL+C */
86 
87 sigaction(SIGUSR1, &sigact, 0); /* catch SIGUSR1 */
88 sigaction(SIGUSR2, &sigact, 0); /* catch SIGUSR1 */
89
90 
91 printf("Program start running for 20 seconds...\\n");
92 alarm(20);
93 
94 while( !g_sigstop )
95 { 
96 ;
97 }
98 
99 printf("Program start stop running...\\n");
100 
101 printf("Invalid pointer operator will raise SIGSEGV signal\\n");
102 *ptr = 'h';
103 
104 return 0;
105 }

注意:kill信号真的是杀死信号吗?
  我们把 kill 理解为杀死一个进程,其实这样的描述是不准确的,kill 其实是作为一个信号,由其中一个进程发给另一个进程,而发送的信号就是终止信号

以上是关于信号(signal)的主要内容,如果未能解决你的问题,请参考以下文章

python signal信号

将 PyQt4 代码适配到 PyQt5,SIGNAL 问题

linux signal

信号---一次实验带出的和signal有关的知识

ECF机制:信号 (Signal)

Linux信号详解:signal与sigaction函数