【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - Linux常见信号及处理
Linux的信号是一种进程间一步通信的机制,在实现上是一种软中断,信号可以导致一个正在运行的进程被异步打断,转而处理一个突发事件。异步事件是不可预见的,只能通过某些特定的方式来预防,或者说,当异步事件发生时根据原来设定完成相应的操作。
Linux常见信号及处理,这里只列出几个:
信号的基本概念
安装信号、安装中断、递送信号、捕获信号、屏蔽信号、忽略信号、未决信号、可靠信号与不可靠信号。详见教材236页。
信号处理流程
(1)信号被某个进程产生,并设置此信号传递的对象(一般为对应进程的pid),然后传递给操作系统;
(2)操作系统根据接收进程的设置(是否阻塞)而选择性的发送给接收者,如果接收者阻塞该信号(且该信号是可以阻塞的),操作系统将暂时保留该信号,而不传递,直到该进程解除对此信号的阻塞(如果对应进程已经退出,则丢弃此信号);如果对应进程没有阻塞,操作系统将传递此信号;
(3)目的进程接收到此信号后,将根据当前进程对此信号设置的预处理方式,暂时终止当前代码的执行,保护上下文(主要包括临时寄存器数据、当前程序位置以及当前CPU的状态)、转而执行中断服务程序,执行完成后再恢复到被中断的位置。当然,对于可抢占式内核,在中断返回时还将引发新的调度。
可能的信号来源
--------发送信号---------
kill发送一个信号到进程
raise自举一个信号
alarm()定时
示例代码:
#include<signal.h> #include<stdio.h> int main(void) { printf("first time return:%d\n",alarm(4)); sleep(1); printf("after sleep(1),remain:%d\n",alarm(2)); printf("renew alarm,remain:%d\n",alarm(1)); }运行结果:
$ ./a.out first time return:0 after sleep(1),remain:3 renew alarm,remain:2
ualarm()定时
示例代码:
#include<unistd.h> #include<signal.h> #include<errno.h> #include<stdio.h> void handler() { printf("int:hello\n"); } int main() { int i; signal(SIGALRM,handler); printf("%d\n",ualarm(300000,100000)); //alarm(2); while(1) { sleep(1); printf("test\n"); } }运行结果:
0$ ./a.out 0 int:hello test int:hello test int:hello test int:hello test 下面省略。。。。。。
setitimer定时器应用
示例代码:
#include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <signal.h> int main(void) { struct itimerval setvalue; setvalue.it_interval.tv_sec=3; setvalue.it_interval.tv_usec=0; setvalue.it_value.tv_sec=3; setvalue.it_value.tv_usec=0; setitimer(ITIMER_REAL,&setvalue,NULL); setvalue.it_interval.tv_sec=3; setvalue.it_interval.tv_usec=0; setvalue.it_value.tv_sec=3; setvalue.it_value.tv_usec=0; setitimer(ITIMER_VIRTUAL,&setvalue,NULL); setvalue.it_interval.tv_sec=3; setvalue.it_interval.tv_usec=0; setvalue.it_value.tv_sec=1; setvalue.it_value.tv_usec=0; setitimer(ITIMER_PROF,&setvalue,NULL); while(1) { struct itimerval value; getitimer(ITIMER_REAL,&value); printf("ITIMER_REAL: internal:%ds%dms,remain:%ds%dms \n",value.it_interval.tv_sec,value.it_interval.tv_usec,value.it_value.tv_sec,value.it_valu e.tv_usec); getitimer(ITIMER_VIRTUAL,&value); printf("ITIMER_VIRTUAL:internal:%ds%dms,remain:%ds%dms \n",value.it_interval.tv_sec,value.it_interval.tv_usec,value.it_value.tv_sec,value.it_valu e.tv_usec); getitimer(ITIMER_PROF,&value); printf("ITIMER_PROF: internal:%ds%dms,remain:%ds%dms\n \n",value.it_interval.tv_sec,value.it_interval.tv_usec,value.it_value.tv_sec,value.it_valu e.tv_usec); sleep(1); } }运行结果:
$ ./a.out ITIMER_REAL: internal:3s0ms,remain:2s999363ms ITIMER_VIRTUAL:internal:3s187ms,remain:3s4187ms ITIMER_PROF: internal:3s187ms,remain:1s62ms ITIMER_REAL: internal:3s0ms,remain:1s998221ms ITIMER_VIRTUAL:internal:3s187ms,remain:3s4187ms ITIMER_PROF: internal:3s187ms,remain:1s62ms ITIMER_REAL: internal:3s0ms,remain:0s997588ms ITIMER_VIRTUAL:internal:3s187ms,remain:3s4187ms ITIMER_PROF: internal:3s187ms,remain:1s62ms 闹钟
注意:
SIGSTOP和SIGKILL这两个信号不能被屏蔽和安装,也就是说,用户不能自定义这两个信号的处理方式。