信号
信号简介
信号是Linux系统中进程间通信的一种方式,用于通知进程发生了某种事件。信号是异步的,可以在任何时候发送给进程。下面是一个简单的例子:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
void handler(int sigNo)
{
printf("get signal:%d\n", sigNo);
}
int main(int argc, char *argv[])
{
signal(SIGINT, handler);
while (1) sleep(1);
return 0;
}
通过signal系统调用给SIGINT信号注册了一个处理函数handler,当进程收到信号后,就执行此处理函数。测试时可以借助kill或killall命令来向指定进程发信号。
信号种类
在linux上一共有64个信号,序号为1-64。使用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
63) SIGRTMAX-1 64) SIGRTMAX
1-31号信号前缀为SIG,32-64号信号前缀为SIGRT。前一组称为标准信号,后一组称为实时信号。所以前缀中RT即实时的意思。
留意到上面列出来的信号好像缺失了32和33号信号。man 7 signal在介绍实时信号部分说明了:
The Linux kernel supports a range of 33 different real-time signals, numbered 32 to 64. However, the glibc POSIX threads implementation internally uses two (for NPTL) or three (for LinuxThreads) real-time signals (see pthreads(7)), and adjusts the value of SIGRTMIN suitably (to 34 or 35). Because the range of available real-time signals varies according to the glibc threading implementation (and this variation can occur at run time according to the available kernel and glibc), and indeed the range of real-time signals varies across UNIX systems,programs should never refer to real-time signals using hard-coded numbers, but instead should always refer to real-time signals using the notation SIGRTMIN+n, and include suitable (run-time) checks that SIGRTMIN+n does not exceed SIGRTMAX.
Linux 内核支持 33 种不同的实时信号,编号从 32 到 64。然而,glibc POSIX 线程实现内部使用了两个(对于 NPTL)或三个(对于 LinuxThreads)实时信号(参见 pthreads(7)),并相应地调整了 SIGRTMIN 的值(到 34 或 35)。由于可用的实时信号范围会根据 glibc 线程实现的不同而变化(并且这种变化在运行时会根据可用的内核和 glibc 发生),并且实时信号的范围在不同的 UNIX 系统中也会有所不同,因此程序不应使用硬编码的数字来引用实时信号,而应始终使用 SIGRTMIN+n 的形式来引用实时信号,并且应包括适当的(运行时)检查,以确保 SIGRTMIN+n 不超过 SIGRTMAX
标准信号
标准信号又称为不可靠信号:这类信号不支持排队,信号处理函数执行期间,相同的信号会被阻塞,如果此时接收到相同信号,信号可能丢失。
实时信号
实时信号又陈可靠信号:和不可靠信号相反,它们支持排队,在执行信号处理函数期间收到的相同信号会排队处理,因此信号不会丢失。
两类信号对比测试
如下测试代码:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void normal_handler(int sigNo)
{
printf("get normal signal:%d\n", sigNo);
sleep(1);
}
void realtime_handler(int sigNo)
{
printf("get realtime signal:%d\n", sigNo);
sleep(1);
}
int main(int argc, char *argv[])
{
signal(SIGQUIT, normal_handler);
signal(SIGRTMIN, realtime_handler);
while (1) sleep(1);
return 0;
}
为了增加信号处理函数的处理时间,故意在里面加了一个sleep(1)。然后执行shell命令:
for i in $(seq 1 10);\
do kill -SIGNAL_NO $(pidof signal_test);\
echo "send SIGINT $i times";\
done
SIGNAL_NO分别替换为SIGQUIT和SIGRTMIN。测试发现,脚本一共发了10次信号,标准信号只处理了2次,而实时信号处理了10次。
我多次修改处理函数的延迟和发送信号的次数,发现它总是只执行两次,需要探究了解一下信号及执行信号处理函数的具体实现,才能解释这一行为。

浙公网安备 33010602011771号