信號處理程序(signal handler)會被重置的信號


  首先說明我的系統,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信號都是同一種處理方式。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM