linux的信号详解
信号概念
定义:
 信号是事件发⽣时对进程的通知机制。
信号产⽣场景:
键盘事件
⾮法内存操作
硬件故障
从⽤户态切换到内核态
信号分类:
标准信号
标准信号的局限性:
1. 阻塞信号可能会丢失。当⼀个信号阻塞时,这个信号即使多次发送给进程,也被执⾏⼀次信号句柄。
2. 信号交付没有携带与信号有关信息。接受到信号的进程⽆法区分同种信号的不同情况,也不知道信号从何⽽来。
3. 信号的交付没有优先级。当有多个信号悬挂与⼀个进程时,交付的顺序不确定。
实时信号
实时信号对标准信号做了⼀下扩充,有以下的特点:
1. 增加了信号从SIGRTMIN到SIGRTMAX的实时信号,可以通过sysconf(_SC_RTSIG_MAX)获得当前操作系统⽀持的实时信
号的个数。
2. 实时信号在队列中并按顺序交付。同⼀类型的实时信号将按顺序交付给进程。
3. 实时信号可以携带额外的信息。
4. 进程能够通过专门的函数更快的回复信号。
5. 当定时器到期、空消息队列有消息到达、有异步IO完成时,信号能够及时交付给进程。
进程收到信号的三种处理⽅式:
1.默认处理:
忽略信号:内核将信号丢弃,信号没有对进程产⽣任何影响
终⽌进程:进程异常终⽌
产⽣核⼼转储⽂件,同时终⽌⽂件
停⽌进程:暂停进程的执⾏
恢复之前暂停的进程继续执⾏
2.忽略处理:
信号来了不做任何处理不能忽略SIGKILL和SIGSTOP
3.捕获并处理:
信号来了捕获信号,并执⾏程序员⾃⼰写的程序不能捕获SIGKILL和SIGSTOP
信号列表:
列表中,编号为1 ~ 31的信号为传统UNIX⽀持的信号,是不可靠信号(⾮实时的),编号为32 ~ 63的信号是后来扩充的,称做可靠信号(实时信号)。不可靠信号和可靠信号的区别在于前者不⽀持排队,可能会造成信号丢失,⽽后者不会。
系统信号详解:
1. SIGHUP
 当终端断开时,将发送该信号给终端控制进程。SIGHUP信号还可⽤于守护进程。
2. SIGINT
 当⽤户键⼊终端中断字符(如:Ctrl + C)终端驱动程序将发送该信号给前台进程组。该信号默认⾏为是终⽌进程。
3. SIGQUIT
 当⽤户在键盘键⼊退出字符(如Ctrl+\)时,该信号将发往前台进程组。默认情况下,该信号终⽌进程,并⽣成可⽤于调试的核⼼转储⽂件。当进程陷⼊⽆限循环或者不在响应,使⽤该信号很合适。
4. SIGILL
 进程试图⾮法执⾏机器语⾔指令,系统将向该进程发送该信号。
5. SIGTRAP
 该信号⽤来实现断点调试功能以及strace命令所执⾏的跟踪系统调⽤功能。
6. SIGABRT
 当进程调⽤abort函数时,系统向该进程发送该信号。默认情况下,该信号会终⽌进程,并产⽣核⼼转储⽂件。
7. SIGBUS
 总线错误,表⽰发⽣了某种内存访问错误。当使⽤mmap()所创建的内存映射时,如果试图访问的地址超出了底层内存映射⽂件的结尾,会产⽣该错误。
8. SIGFPE
 在发⽣致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。
9. SIGKILL
 此信号为必杀信号,处理器程序⽆法阻塞、忽略或者捕获,故⽽总能杀死进程(僵⼫进程除外)。
10. SIGUSR1
 ⽤户⾃定义信号,内核绝不会为进程产⽣该信号。
11. SIGSEGV
 试图访问未分配给⾃⼰的内存, 或试图往没有写权限的内存地址写数据.
12. SIGUSR2
12. SIGUSR2
 同SIGUSR1描述。
13. SIGPIPE
 当某⼀进程试图向管道,FIFO或套接字写⼊信息时,如果这些设备并⽆相应的阅读进程,系统将产⽣该信号。(管道破裂)
14. SIGALRM
 经调⽤alarm()或setitimer()⽽设置的实时定时器⼀旦到期,内核将产⽣该信号。
15. SIGTERM
 这是⽤来终⽌进程的标准信号,也是kill和killall命令所发送的默认信号。⽤户经常会使⽤kil -9显⽰向进程发送SIGKILL信号,然⽽这⼀做法通常是错误的。精⼼设计的应⽤程序应当为SIGTERM信号设置处理器程序,以便于其能够预先清理临时⽂件和释放资源,做到全⾝⽽退。发送SIGKILL信号可以杀掉某个进程,从⽽绕开了SIGTERM的信号处理程序。因此,总是应该⾸先尝试使⽤SIGTERM 信号来终⽌进程,⽽把SIGKILL信号作为最后⼿段,去对付那些失控的进程。
16. SIGSTKFLT
 linux对该信号做了定义,但并未加以使⽤。
17. SIGCHLD
 当⽗进程的某⼀⼦进程退出时,内核将向⽗进程发送该信号。
18. SIGCONT
 该信号发送给已停⽌的进程,进程将恢复运⾏。当接收信号的进程当前处于⾮停⽌状态 时,默认情况下将忽略该信号。
19. SIFSTOP
 进程收到该信号将停⽌运⾏,处理器程序⽆法将其阻塞、忽略或者捕获,故⽽总能停⽌进程。
20. SIGTSTP
 作业控制的停⽌信号,当⽤户在键盘输⼊挂起字符(如:Ctrl+Z)时,将发送该信号给前台进程组,使其停⽌运⾏。(该信号可以被处理和忽略)
21. SIGTTIN
 在作业控制shell下运⾏时,若后台进程组试图对终端进⾏read()操作,终端驱动程序则将该进程组发送该信号。该信号默认将停⽌进程。
22. SIGTTOU
 该信号与SIGTTIN类似,但在写终端(或修改终端模式)时收到。
23. SIGURG
 系统发送该信号给⼀个进程,表⽰套接字上存在带外(紧急)数据。
24. SIGXCPU
 当进程的CPU时间超出对应的资源限制时,将发送此信号给进程。
25. SIGXFSZ
 如果进程试图增⼤⽂件⽽突破对进程⽂件⼤⼩的资源限制时,将发送该信号给进程。
26. SIGVTALRM
 虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占⽤的CPU时间。
27. SIGPROF
 类似于SIGALRM/SIGVTALRM, 但包括该进程⽤的CPU时间以及系统调⽤的时间.
28. SIGWINCH
 窗⼝⼤⼩改变时发出该信号。
29. SIGIO
 ⽂件描述符准备就绪, 可以开始进⾏输⼊/输出操作。
30. SIGPWR
 电源故障信号。
31. SIGSYS
 如果进程发起的系统调⽤有误,将产⽣该信号。
操作信号
使⽤命令发送信号给进程
kill -信号进程id
kill命令是使⽤kill函数实现的。
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
pid:指定哪个进程
pid>0:会发送信号给指定进程号为pid的进程。
pid=0:发送信号给调⽤进程组同组的每个进程,包括调⽤进程本⾝。
pid=-1:调⽤进程有权将信号发往的每⼀个进程,除去init(1号进程)和调⽤进程⾃⾝。如果特权级进程发起这⼀调⽤,那么会将信号发给系统中所有进程。有时也称这种信号称为⼴播信号。
pid<-1:会向该pid绝对值的进程组下属进程发送信号。
sig:发送哪个信号
kill还有⼀个特殊的⽤途:当sig=0时,表⽰⽆信号发送,调⽤kill()函数会去执⾏错误检查,查看是否可以向⽬标进程发送信号。这也就意味着可以指定空信号来检测ID进程是否存在。
给本进程发信号:
#include <signal.h>
int raise(int sig);
调改变信号处置:
系统调⽤函数
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
参数:
signum:表⽰希望修改的信号编号
handler:表⽰信号到达时执⾏的处理器程序的地址,该函数⽆返回值。
  1. ⾃定义函数
  2.SIG_DFL:将信号处置重置为默认值。这适⽤于将之前signal()调⽤所改变的信号处置还原。
  3.SIG_IGN:忽略该信号。
handler⼀般格式:
void handler(int sig)
{
//处理程序
}
返回值:
linux下的sleep函数成功:signal()的返回值是之前的信号处置,像handler参数⼀样,是⼀个指针,指向的是带有⼀个整形参数且⽆返回值的函数。
失败:返回SIG_ERR
信号处理器程序介绍
 信号处理器程序时当指定信号传递给进程时将会调⽤的⼀个函数。
调⽤信号处理程序,可能会随时打断主程序流程,内核代表进程来调⽤处理器程序,当处理器程序返回时,主程序会在打断的位置处恢复执⾏。
信号处理器程序设计原则:⼒求简单。
⽰例代码:
void handler(int sig) //处理器程序
{
printf("ctrl + c\n");
}
int main()
{
int sig = SIGINT; //信号
if(signal(sig,handler) == SIG_ERR)
perror("signal"),exit(1);
int i = 0;
while(1)
{
printf("%c ",i%26+'a');
fflush(stdout);
i++;
sleep(1);
}
return0;
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。