Linux编程之信号处理

本文详细探讨了Linux编程中的信号处理,包括信号的默认处理方式、自定义信号处理函数、信号发送、EINTR处理、信号掩码、fork与信号的关系、僵尸进程与SIGCHLD以及实时信号。通过示例代码展示了如何使用signal和sigaction函数注册信号处理,以及处理信号中断的策略。此外,还讨论了多线程环境下信号处理的特点,强调了线程间信号处理的协同和选择。
摘要由CSDN通过智能技术生成

 

Linux系统中的信号

在Linux编程中,信号是不可避免的一个话题。信号是一种软中断机制,在应用程序运行的任意时刻都可能产生一个信号。信号产生后,进程会被打断去处理信号。每个信号都有一个当前的处理方式,不同的处理方式所产生的结果也不同。总结起来,信号的处理方式有以下几种:

  • 终止进程
  • 忽略信号
  • 进程转储
  • 停止进程
  • 恢复进程

在Linux系统中,每种信号都有一个默认的处理方式。在程序中可以改变信号的默认处理方式,详细内容可查看下一节处理信号。那么怎么知道系统中支持那些信号呢?最简单的方式就是用"kill -l"命令来获取系统支持的信号列表。这个命令在UNIX、BSD、Linux等系统上都是可用的,而且在不同系统上得到的结果可能不一样。下面分别在Linux系统和macOS(基于BSD)系统上得到的信号列表。

kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL
 5) SIGTRAP	 6) SIGABRT	 7) SIGEMT	 8) SIGFPE
 9) SIGKILL	10) SIGBUS	11) SIGSEGV	12) SIGSYS
13) SIGPIPE	14) SIGALRM	15) SIGTERM	16) SIGURG
17) SIGSTOP	18) SIGTSTP	19) SIGCONT	20) SIGCHLD
21) SIGTTIN	22) SIGTTOU	23) SIGIO	24) SIGXCPU
25) SIGXFSZ	26) SIGVTALRM	27) SIGPROF	28) SIGWINCH
29) SIGINFO	30) SIGUSR1	31) SIGUSR2

在Linux系统中,对常见信号都有一个默认的处理方式。详见下表。

       信号             值             处理方式   说明
       ──────────────────────────────────────────────────────────────────────
       SIGHUP       1              终止进程    控制终端挂起或者控制进程死亡
       SIGINT         2              终止进程    键盘中断,如按下ctrl+c
       SIGQUIT      3              进程转储    从键盘收到退出ctrl+\ 或者 SysRq
       SIGILL         4              进程转储    非法指令
       SIGABRT     6              进程转储    中止信号,比如在程序中调用abort()
       SIGFPE        8              进程转储    浮点异常,比如除数为0
       SIGKILL        9              终止进程    Kill信号
       SIGSEGV     11             进程转储    非法内存引用
       SIGPIPE       13             终止进程    断裂的管道
       SIGALRM     14             终止进程    警告信号,比如在程序中调用alarm()
       SIGTERM      15            终止进程    终止信号
       SIGUSR1      30,10,16   终止进程    用户自定义信号1
       SIGUSR2      31,12,17   终止进程    用户自定义信号2
       SIGCHLD      20,17,18  忽略信号     子进程停止或者退出
       SIGCONT     19,18,25   恢复进程     恢复信号
       SIGSTOP     17,19,23    停止进程    停止信号
       SIGTSTP      18,20,24    停止进程    终端输入停止
       SIGTTIN       21,21,26    停止进程    后台进程的终端输入
       SIGTTOU     22,22,27    停止进程    后台进程的终端输出

       SIGBUS       10,7,10     进程转储     总线错误
       SIGPOLL                      终止进程     可轮询时间
       SIGPROF     27,27,29   终止进程    性能计数定时器到时
       SIGSYS       12,31,12    进程转储    错误的系统调用
       SIGTRAP     5               进程转储    调试跟踪/断点陷阱
       SIGURG      16,23,21    忽略信号    socket上的紧急情况

 

对于大多数信号,一般情况下默认的处理方式都适用。但是有些信号在特定的程序设计中默认处理方式可能并不适用。以下是几个例子:

  • SIGHUP: SIGHUP通常在控制终端退出或者断开时会产生。一个典型的例子是,你ssh登陆到一个服务器上,在后台启动一个服务程序;然后断开ssh连接,此时后台服务程序会收到SIGHUP信号。而默认的处理方式服务程序将终止,但是这也许并不是期望的行为。为了避免在收到SIGHUP信号时退出,需要自定义处理SIGHUP信号。当然,另外一个方法是采用nohup工具来启动服务程序。nohup本质上也是忽略SIGHUP信号。
  • SIGPIPE:在使用socket的网络程序中,SIGPIPE信号可能会产生。一个典型的例子是,一个TCP的Client正连着一个Server发送数据,此时Server关闭socket,那么Client的send函数操作会触发一个SIGPIPE信号。而SIGPIPE的默认处理程序将结束Client程序。多数情况下,这种处理方式并不恰当,因为Client可能还想尝试重连或者连接其它Server。因此这种情况下就需要针对SIGPIPE进行自定义处理。
  • SIGTERM: SIGTERM的一个典型场景时系统关机或者重启前,Linux的init进程(PID为1的进程)会先向所有进程发送SIGTERM信号,然后再发送SIGKILL信号。因此,如果一个程序想要优雅地关闭,比如一个程序或许想在关闭前存储一些状态以便在下次启动时使用,那么处理SIGTERM是一个很好的时机。

 

前面提到通过命令"kill -l"可以获取系统中的信号列表,下面的程序代码则演示了在C语言中获取信号列表及相关信息的方法。

/*
 * sig_list.c: demostrates listing signals in system.
 */
#include <signal.h>
#include <stdio.h>

static void list_signals(void)
{
	int sig;
	sigset_t ss;
	sigfillset(&ss);
	for (sig = 0; sig < NSIG; sig++) {
#ifdef __DARWIN_C_LEVEL
		printf("%-12s %-2d  %-32s valid: %s\n", sys_signame[sig] ? sys_signame[sig] : " ", sig,
				sys_siglist[sig] ? sys_siglist[sig] : " ", sigismember(&ss, sig) ? "yes" : "no");
#else
		printf("%-2d  %-32s valid: %s\n", sig, sys_siglist[sig] ? sys_siglist[sig] : " ", sigismember(&ss, sig) ? "yes" : "no");
#endif
	}
}

int main(int argc, char *argv[])
{
	list_signals();
	return 0;
}

将源码编译生成sig_list程序。

gcc -o sig_list sig_list.c

在Linux和macOS上分别编译运行这个程序,得到的结果是不同的,如下所示。

./sig_list
0                                    valid: yes
1   Hangup                           valid: yes
2   Interrupt                        valid: yes
3   Quit                             valid: yes
4   Illegal instruction              valid: yes
5   Trace/breakpoint trap            valid: yes
6   Aborted                          valid: yes
7   Bus error                        valid: yes
8   Floating point exception         valid: yes
9   Killed                           valid: yes
10  User defined signal 1            valid: yes
11  Segmentation fault               valid: yes
12  User defined signal 2            valid: yes
13  Broken pipe                      valid: yes
14  Alarm clock                      valid: yes
15  Terminated                       valid: yes
16  Stack fault                      valid: yes
17  Child exited                     valid: yes
18  Continued                        valid: yes
19  Stopped (signal)                 valid: yes
20  Stopped                          valid: yes
21  Stopped (tty input)              valid: yes
22  Stopped (tty output)             valid: yes
23  Urgent I/O condition             valid: yes
24  CPU time limit exceeded          valid: yes
25  File size limit exceeded         valid: yes
26  Virtual timer expired            valid: yes
27  Profiling timer expired          valid: yes
28  Window changed                   valid: yes
29  I/O possible                     valid: yes
30  Power failure                    valid: yes
31  Bad system call                  valid: yes
32                                   valid: no
33                                   valid: no
34                                   valid: yes
35                                   valid: yes
36                                   valid: yes
37                                   valid: yes
38                                   valid: yes
39                                   valid: yes
40                                   valid: yes
41                                   valid: yes
42                                   valid: yes
43                                   valid: yes
44                                   valid: yes
45                                   valid: yes
46                                   valid: yes
47                                   valid: yes
48                                   valid: yes
49                                   valid: yes
50                                   valid: yes
51                                   valid: yes
52                                   valid: yes
53                                   valid: yes
54                                   valid: yes
55                                   valid: yes
56                                   valid: yes
57                                   valid: yes
58                                   valid: yes
59                                   valid: yes
60                                   valid: yes
61                                   valid: yes
62                                   valid: yes
63                                   valid: yes
64                                   valid: yes
./sig_list
Signal 0     0   Signal 0                         valid: yes
hup          1   Hangup                           valid: yes
int          2   Interrupt                        valid: yes
quit         3   Quit                             valid: yes
ill          4   Illegal instruction              valid: yes
trap         5   Trace/BPT trap                   valid: yes
abrt         6   Abort trap                       valid: yes
emt          7   EMT trap                         valid: yes
fpe          8   Floating point exception         valid: yes
kill         9   Killed                           valid: yes
bus          10  Bus error                        valid: yes
segv         11  Seg
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值