zoukankan      html  css  js  c++  java
  • 【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

      运行结果

      

      

  • 相关阅读:
    DataTable:数据库到程序的桥梁
    《Javascript高级程序设计》阅读记录(三):第五章 上
    《Javascript高级程序设计》阅读记录(二):第四章
    javascript获取窗口位置、绝对位置、事件位置等
    《Javascript高级程序设计》阅读记录(一):第二、三章
    调试用随笔
    C#值类型和引用类型
    vue使用vue-awesome-swiper及一些问题
    npm与yarn命令对比
    npm与nrm
  • 原文地址:https://www.cnblogs.com/life91/p/3114945.html
Copyright © 2011-2022 走看看