标签:
首先说明我的系统,CentOS 6.6,内核为2.6.32-504.12.2.el6.i686。
当用signal对某个信号设定信号处理函数的时候,有些信号的处理函数会被重置,有些则不会,这种情况的具体说明我还没有找到,这里我就先列一下我找到的几个信号。
信号处理程序会被重置的信号:
1. SIGALRM
比如下面这段代码,这段代码的作用就是给自己发送SIGALRM信号,直到发送了NUM次。
1 #include <errno.h> 2 #include <pwd.h> 3 #include <signal.h> 4 #include <string.h> 5 #include <stdlib.h> 6 #include <stdarg.h> 7 #include <stdio.h> 8 #include <sys/types.h> 9 #include <unistd.h> 10 11 #define BUFSIZE 512 12 #define NUM 5 13 14 /* 15 * 这三个函数是我自定义的,功能就是利用strerror打印errno的信息,并且退出 16 */ 17 void err_exit(char *fmt,...); 18 int err_dump(char *fmt,...); 19 int err_ret(char *fmt,...); 20 21 int alrm_count = 0; //对发送的alrm信号进行计数 22 /* 23 * 本函数用来处理SIGALRM信号 24 */ 25 void sig_alrm(int signo) 26 { 27 alrm_count++; 28 printf("In signal SIGALRM handler\n"); 29 if(SIG_ERR == signal(SIGALRM,sig_alrm)) 30 err_exit("[signal]: "); 31 if(alrm_count < NUM) { 32 alarm(1); 33 pause(); 34 } 35 } 36 37 int main(int argc,char *argv[]) 38 { 39 if(SIG_ERR == signal(SIGALRM,sig_alrm)) 40 err_exit("[signal]: "); 41 42 /*alarm函数的功能就是在1s之后向本进程发送一个SIGALRM信号*/ 43 alarm(1); 44 pause(); 45 46 return 0; 47 }
这个程序的29~30行就是在信号的处理函数中重新设置对SIGALRM的处理函数,下次产生SIGALRM这个信号的时候,继续来调用这个处理函数。程序的运行结果如下:
如果没有29~30行那两行的内容,程序的运行结果就会变成下面这样:
第一次接受到SIGALRM信号,程序会调用我们自定义的sig_alrm信号处理函数,但是第二次接受到SIGALRM信号的时候,程序就会调用系统默认的SIGALRM的信号处理函数了,此时就会打印出Alarm clock信息。
2. SIGCHLD信号(SIGCLD)
在linux下面,这两个信号是等价的,所以就放在一起来讨论。首先先把代码贴上来:
1 #include <errno.h> 2 #include <signal.h> 3 #include <string.h> 4 #include <stdlib.h> 5 #include <stdarg.h> 6 #include <stdio.h> 7 #include <sys/types.h> 8 #include <sys/wait.h> 9 #include <unistd.h> 10 11 #define BUFSIZE 512 12 #define NUM 2 13 14 void err_exit(char *fmt,...); 15 int err_dump(char *fmt,...); 16 int err_ret(char *fmt,...); 17 18 void sig_chld(int signo); 19 20 int main(int argc,char *argv[]) 21 { 22 pid_t pid; 23 24 if(SIG_ERR == signal(SIGCHLD,sig_chld)) 25 perror("[signal]: "); 26 27 for(int loop=0;loop<NUM;loop++) { 28 if(-1 == (pid=fork())) { 29 err_exit("[fork]:"); 30 } else if(0 == pid) { 31 printf("I‘m the No.%d Child %d\n",loop+1,getpid()); 32 return 0; 33 } else { 34 pause(); 35 } 36 } 37 38 return 0; 39 } 40 41 void sig_chld(int signo) 42 { 43 int status; 44 pid_t cpid; 45 46 /* printf("A child process terminated!\n"); */ 47 if(-1 == (cpid=wait(&status))) 48 err_exit("[wait]: "); 49 else 50 printf("Process %d terminated!\n",cpid); 51 52 if(SIG_ERR == signal(SIGCHLD,sig_chld)) 53 perror("[signal]: "); 54 }
这段代码的作用就是父进程创建一个子进程,然后暂停,等待子进程结束发送SIGCHLD信号过来,在SIGCHLD信号的信号处理函数中,将子进程回收,并且打印出回收的子进程进程id。执行完这些步骤之后,再来继续这个过程,直到循环了NUM次。
这个程序的运行结果如下所示:
这里可以看到,两个子进程结束时发送的SIGCHLD信号都被接受到了,并且两个子进程都被回收了。
如果我去掉了在信号处理函数中的signal函数(52~53行),那么程序的运行结果就会如下图所示:
主函数卡死了,此时我用top命令来查看这进程信息,发现第二个子进程变成了僵尸进程,如下图所示:
此时SIGCHLD信号处理函数,变成了默认的忽略(SIG_IGN),接受到了SIGCHLD信号就不会调用函数了,而pause函数的说明则是这样的:
pause函数只有遇到让主进程终止的信号,或者是产生信号处理函数调用的函数才会停止睡眠。而在上面的程序中,第二次的时候SIGCHLD信号由于采用的系统默认的配置SIG_IGN,此时不会产生信号处理函数的调用,所以主进程就继续暂停。
信号处理程序不会被重置的信号:
目前我只发现了两个,就是两个用户自定义的函数,SIG_USR1和SIG_USR2,具体可以参看下面这段代码:
1 #include<errno.h> 2 #include<signal.h> 3 #include<string.h> 4 #include<stdlib.h> 5 #include<stdarg.h> 6 #include<stdio.h> 7 #include<unistd.h> 8 9 #define BUFSIZE 512 10 11 /* 12 * 这三个函数是我自定义的,功能就是利用strerror打印errno的信息,并且退出 13 */ 14 void err_exit(char *fmt,...); 15 void err_dump(char *fmt,...); 16 int err_ret(char *fmt,...); 17 18 void sig_handler(int signo) 19 { 20 if(signo == SIGUSR1) 21 printf("Catch the SIGUSR1 [%d]\n",signo); 22 else if(signo == SIGUSR2) 23 printf("Catch the SIGUSR2 [%d]\n",signo); 24 else 25 err_dump("Catch the signal %d\n",signo); 26 } 27 int main(int argc,char *argv[]) 28 { 29 if(SIG_ERR == signal(SIGUSR1,sig_handler)) 30 err_exit("[signal]1: "); 31 if(SIG_ERR == signal(SIGUSR2,sig_handler)) 32 err_exit("[signal]2: "); 33 34 for(;;) 35 pause(); 36 37 return 0; 38 }
这个程序就是一直等待信号发送过来,并且会对SIGUSR1和SIGUSR2进行处理,其他信号则会执行系统默认的处理情况。运行的结果如下图:
程序开始后,我通过另一个终端给这个程序发送信号,如下图所示:
而程序运行的界面如下图所示:
从这里可以看出,我们只对SIGUSR这两个函数设置了一次信号处理函数,但是它们的处理方式就不会被重置,发送多次SIGUSR信号都是同一种处理方式。
标签:
原文地址:http://www.cnblogs.com/bwangel23/p/4439671.html