一、信号产生种类
1、特殊终端按键
Ctrl+C SIGINT
Crtl+Z SIGTSTP
Ctrl+\ SIGQUIT
2、硬件异常
除0操作
访问非法内存
3、Kill函数或者kill指令
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
pid参数说明
Pid参数 |
说明 |
Pid > 0 |
Sig发送给ID为pid的进程 |
Pid = 0 |
Sig信号发送给与调用kill的那个进程同组的所有进程 |
Pid = -1 |
sig信号将送往所有调用进程有权给其发送信号的进程,除了进程1(init)。 |
Pid < -1 |
sig发送给组ID为|-pid|的进程,并且发送进程具有向其发送信号的权限 |
sig参数为kill –l看到的前32个信号
4、某种软件条件已经发生
比喻定时器定时1s
1. #include <stdio.h> 2. #include <unistd.h> 3. 4. 5. int main(void) 6. { 7. int counter; 8. alarm(1); 9. /* 10. 11. sleep(1)与alarm(1)的区别 12. sleep(1)就是睡在这里,下面的代码不去执行 13. alarm(1)只是定时1s,下面的代码还是会继续执行 14. */ 15. 16. for(counter=0; 1; counter++) 17. printf("counter = %d.\n", counter); 18. 19. return 0; 20. }
二、进程处理信号行为
manpage里信号有3种处理方式
1.默认处理动作(man 7 signal可以看到)
term 终止此信号
core 终止当前进程并且产生段错误
ign 忽略此信号
stop 暂停(挂起)此信号
cont 继续此进程的执行(暂停之后继续)
2.忽略
3.捕捉(用户自定义信号处理函数,类似于中断服务程序)
三、信号处理函数
实际执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)。进程可以选择阻塞(Block)某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
下图给出信号从产生到抵达的执行过程
1、阻塞信号集是用户可以设置的,未决信号集是用户不能设置的;
2、系统规定有2个信号不能被阻塞,SIGKILL和SIGSTOP
3、内核向进程发送一个信号,到信号的执行过程分为以下步骤
(1)首先未决信号集对应的信号位会置1,
(2)去判断阻塞信号集对应的信号位是否为1,若为1则阻塞,若为0则信号递达,并执行handle
(3)当执行完之后,未决信号集对应的信号位被翻转成0
4、未决和阻塞标志都可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可表示每个信号的“有效”或“无效”状态。阻塞信号集中“有效”和“无效”分别表示该信号是否被阻塞;未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。
5、阻塞信号集也叫当前进程的信号屏蔽字(Signal mask),这里的屏蔽应该理解为阻塞而不是忽略。
四、C标准库提供的信号处理函数
signal函数和system函数
1. typedef void (*sighandler_t)(int) 2. 3. sighandler_t signal(int signum, sighandler_t handler)
程序:
1. #include <stdio.h> 2. #include <signal.h> 3. #include <unistd.h> 4. 5. 6. void do_sig(int n) 7. { 8. printf("hello.\n"); 9. } 10. 11. int main(void) 12. { 13. signal(SIGINT,do_sig); 14. 15. while(1){ 16. printf("*******************\n"); 17. sleep(1); 18. } 19. 20. return 0; 21. }
执行结果如下:
按下Ctrl+C 发送SIGINT信号,执行do_sig函数,打印hello