【Linux 编程】Linux信号处理

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

【Linux 编程】Linux信号处理

图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

  运行结果

  【Linux 编程】Linux信号处理

  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

  运行结果

  【Linux 编程】Linux信号处理

  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

  运行结果

  【Linux 编程】Linux信号处理

 

  

你可能感兴趣的:(linux)