【Linux 编程】Linux信号处理

  信号驱动式I/O是指进程预先告知内核,使得当某个描述字上发生某事时,内核使用信号通知相关进程。图1概括展示信号驱动式I/O模型。

图1 信号驱动式I/O模型

  针对一个进程建立一个相关进程的处理函数,需要通过signal()函数来建立。

  基本信号:(linux 控制台中输入:man 7 signal)

  SIGINT(值为2,默认动作:terminal):Interrupt from keyboard。

  SIGTERM(值为15,默认动作:terminal):Termination signal

  SIGCHILD(值为20,17,28,默认动作:ignore):child stopped or terminated。

  其中,SIGINT信号是由用户按中断键(即DELETE或ctrl+c)时,终端驱动程序产生此信号并发送至前段进程组中的每一个进程。

  SIGCHLD信号,在一个进程终止或停止时,将SIGCHLD发送给其父进程。

  SIGTERM信号,由kill(1)命令发送的系统默认终止信号。

  在系统提供的信号值是从0至31,即4 bytes大小。但是用户可以自己设置超过该范围的信号,通过kill -ith pidno来触发新建立的信号。

  利用kill来触发信号处理函数,是因为信号实际上就是一个位数组中相应位来建立是否被触发。例如,sigdelset函数

 1 int sigdelset( sigset_t *set, int signo )
 2 {
 3     if ( SIGBAD( signo ) )
 4     {
 5         errno = EINVAL;
 6         return (-1);
 7     }
 8     
 9     // 该语句帮助理解sigset_t变量实际上就是一个位数组。
10     *set &= ~(1 << (signo - 1)); 
11     
12     return 0;
13 }
View Code

  建立超过31th的信号处理函数与正常的信号处理函数相同,只是触发方式为:kill -ith pidno

 1 #include <signal.h>
 2 #include <stdio.h>
 3 
 4 static void sig_default(int);
 5 
 6 int main()
 7 {
 8     sigset_t set;
 9     sigemptyset(&set);
10     sigfillset(&set);
11     sigdelset(&set, 36);
12     sigdelset(&set, 37);
13     sigdelset(&set, 38);
14     sigprocmask(SIG_SETMASK, &set, NULL);
15 
16     if (signal(36, sig_default) == SIG_ERR) 
17     {
18         perror("can not reset the 36th signal handler");
19         return 1;
20     }
21 
22     if (signal(37, sig_default) == SIG_ERR)
23     {
24         perror("can not reset the 37th signal handler");
25         return 1;
26     }
27 
28     if (signal(38, sig_default) == SIG_ERR)
29     {
30         perror("can not reset the 38th signal handler");
31         return 1;
32     }
33 
34     while (1)
35     {
36         pause();
37     }
38 
39     return 0;
40 }
41 
42 static void sig_default(int signo)
43 {
44     if (signo == 36)
45         printf(" 36th signal\n");
46     else if (signo == 37)
47         printf(" 37th signal\n");
48     else if (signo == 38)
49         printf(" 38th signal\n");
50     else
51         printf(" Unknown signal\n");
52 
53     return ;
54 }
View Code

  其运行结果

  

  

  下面来考虑,主进程利用fork()函数来建立的子进程是否继承父进程的信号处理函数

  1. 若在子进程中,没有清楚父进程建立的响应的信号处理函数,则继承父进程的信号处理函数。

  

 1 #include <unistd.h>
 2 #include <signal.h>
 3 #include <stdio.h>
 4 
 5 /* In this file:
 6  * We test child process created by fork().
 7  * The child process whether inherit signal 
 8  * process of parent process or not.
 9  * 
10  * This file not clear signal set.
11  */
12 static void sig_parent(int signo)
13 {
14     if (signo == 36)
15         printf(" this is parent signal\n");
16     else if (signo == 37)
17         printf(" this is children signal\n");
18     else
19         printf(" Unkown signal\n");
20 
21     return ;
22 }
23 
24 void ChildProc()
25 {
26     printf(" child process id is %d\n", getpid());
27     if (signal(37, sig_parent) == SIG_ERR)
28     {
29         perror(" can not reset the 37th signal handler\n");
30         return;
31     }
32 
33     while (1) pause();
34 
35     return;
36 }
37 
38 int main()
39 {
40     pid_t pid;
41 
42     if (signal(36, sig_parent) == SIG_ERR)
43     {
44         perror(" can not reset the 36th signal handler\n");
45         return -1;
46     }
47 
48     if ((pid = fork()) < 0)
49         perror(" failed to fork()\n");
50     else if (pid == 0){
51         ChildProc();
52         return 0;
53     } else 
54         while (1)  pause();
55 
56     return 0;
57 }
View Code

  运行结果

  

  2. 若在进程中,利用sigemptyset()、sigfillset()、sigdelset()、sigprocmask()等函数来清理并设置新的触发位,则不继承父进程的信号处理函数

  

 1 #include <unistd.h>
 2 #include <signal.h>
 3 #include <stdio.h>
 4 
 5 /* In this file:
 6  * We test child process created by fork().
 7  * The child process whether inherit signal 
 8  * process of parent process or not.
 9  * 
10  * This file will clear signal headler.
11  */
12 static void sig_parent(int signo)
13 {
14     if (signo == 36)
15         printf(" this is parent signal\n");
16     else if (signo == 37)
17         printf(" this is children signal\n");
18     else
19         printf(" Unkown signal\n");
20 
21     return ;
22 }
23 
24 void ChildProc()
25 {
26     sigset_t set;
27     sigemptyset(&set);
28     sigfillset(&set);
29     sigdelset(&set, 37);
30     sigprocmask(SIG_SETMASK, &set, NULL);
31     
32     printf(" child process id is %d\n", getpid());
33     if (signal(37, sig_parent) == SIG_ERR)
34     {
35         perror(" can not reset the 37th signal handler\n");
36         return;
37     }
38 
39     while (1) pause();
40 
41     return;
42 }
43 
44 int main()
45 {
46     pid_t pid;
47 
48     if (signal(36, sig_parent) == SIG_ERR)
49     {
50         perror(" can not reset the 36th signal handler\n");
51         return -1;
52     }
53 
54     if ((pid = fork()) < 0)
55         perror(" failed to fork()\n");
56     else if (pid == 0){
57         ChildProc();
58         return 0;
59     } else 
60         while (1)  pause();
61 
62     return 0;
63 }
View Code

  运行结果

  

  3. 若在继承父进程的信号处理函数的情况下,设置与父进程相同的信号位。将屏蔽父进程的信号处理函数。

 1 #include <unistd.h>
 2 #include <signal.h>
 3 #include <stdio.h>
 4 
 5 static void sig_parent(int signo)
 6 {
 7     if (signo == 36)
 8         printf(" this is parent signal handler\n");
 9     else
10         printf(" Unkown signal\n");
11 
12     return ;
13 }
14 
15 static void sig_child(int signo)
16 {
17     if (signo == 36)
18         printf(" this is child signal handler\n");
19     else
20         printf(" unkown signal\n");
21     
22     return;
23 }
24 
25 void ChildProc()
26 {
27     printf(" child process id is %d\n", getpid());
28     if (signal(36, sig_child) == SIG_ERR)
29     {
30         perror(" can not reset the 37th signal handler\n");
31         return;
32     }
33 
34     while (1) pause();
35 
36     return;
37 }
38 
39 int main()
40 {
41     pid_t pid;
42 
43     if (signal(36, sig_parent) == SIG_ERR)
44     {
45         perror(" can not reset the 36th signal handler\n");
46         return -1;
47     }
48 
49     if ((pid = fork()) < 0)
50         perror(" failed to fork()\n");
51     else if (pid == 0){
52         ChildProc();
53         return 0;
54     } else 
55         while (1)  pause();
56 
57     return 0;
58 }
View Code

  运行结果

  

  

原文地址:https://www.cnblogs.com/life91/p/3114945.html