• Linux 进程学习(三)


    捕捉信号:
      
     
    使用 signal 函数
     signal 函数是 Linux 系统上传统的信号处理接口:
     #include <signal.h>
     sighandler_t signal(int signum, sighandler_t handler);

     其中 sighandler_t 类型是一个函数指针类型,定义如下:
     typedef void (*sighandler_t)(int);

     这个类型表示一个信号处理函数。signal 函数的作用就是讲 handler 参数所指向的函数注册成为参数

    signum 所代表的信号的处理函数,它的返回值是这个信号原来的处理函数,如果返回 SIG_ERR,则说明有错误发生,
    注册失败。
     注册成功后,所注册的函数就会在信号被处理时调用,代替了默认的行为,或者成为信号被捕捉。 
     
     使用 signal 函数时应注意以下两点:
     ◆ handler 参数的值可以是 SIG_IGN 或者 SIG_DFL,SIG_IGN 表示忽略这个信号,SIG_DFL 表示对信号的处

    理重设为系统的默认方式。
     ◆ 有些信号是不可以忽略或捕获的,如 SIGKILL 和 SIGSTOP。

     下面给出一个例程来说明信号的产生、忽略与捕获的编程,例程代码如下:

      1 /* 文件名:sigtest.c */
      2 /* 说明:信号处理例程 */
      3 
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <signal.h>
      7 #include <unistd.h>
      8 #include <sys/wait.h>
      9 
     10 static pid_t pid;
     11 
     12 /* 子进程 1 SIGALRM 信号处理函数 */
     13 static void wakeup(int dummy)
     14 {
     15     printf("I (pid = %d) am up now\n",pid);
     16 }
     17 
     18 /* 子进程 1 SIGINT 信号处理函数 */
     19 static void handler(int dummy)
     20 {
     21     printf("I (pid = %d) got an interrupt, will exit\n",pid);
     22     exit(0);
     23 }
     24 
     25 /* 子进程 2 信号处理函数 */
     26 static void trapper(int i)
     27 {
     28     if(i == SIGUSR1)
     29     {
     30         printf("I (pid = %d) got SIGUSR1,will exit\n", pid);
     31         exit(0);
     32     }
     33     else
     34     {
     35         printf("I (pid = %d) got signal %d, will continue\n", pid, i);
     36     }
     37 }
     38 
     39 
     40 /* 父进程信号处理函数 */
     41 void parent(int sig)
     42 {
     43     printf("Signal (%d) received by parent (%d)\n", sig, pid);
     44 }
     45 
     46 int main(int argc, char *argv[])
     47 {
     48     int i, cpid1, cpid2;
     49     
     50     printf("Number of signal is %d\n", NSIG);   //输出系统中信号的个数
     51     
     52     if(!(cpid1 = fork()))  //创建第一个子进程
     53     {
     54         pid = cpid1 = getpid();  //获得子进程的进程号
     55         printf("CPID1 = %d\n", cpid1);
     56         
     57         for(i=1; i<NSIG; i++)
     58         {
     59             signal(i, SIG_IGN);  //忽略所以的信号
     60         }
     61         
     62         signal(SIGINT, handler); //捕获信号 SIGINT
     63         signal(SIGALRM, wakeup); //捕获超时信号
     64         alarm(2);                //启动定时器,设置 2 秒后超时
     65         
     66         for(; ;)
     67         {
     68             pause();  //等待信号
     69         }
     70         
     71         printf(" -- CPID1 (%d) terminates\n", cpid1);
     72         
     73         exit(0);
     74     }
     75     else if(!(cpid2 = fork()))  //创建第二个子进程
     76     {
     77         pid = cpid2 = getpid();
     78         printf("CPID2 = %d\n", cpid2);
     79         
     80         for(i=1; i<NSIG; i++)
     81         {
     82             signal(i, trapper);  //捕获所有的信号
     83         }
     84         
     85         for(; ;)
     86         {
     87             pause();  //等待信号
     88         }
     89         
     90         printf(" -- CPID2 (%d) terminates\n", cpid2);
     91         
     92         exit(0);
     93     }
     94     
     95     /* 下面是父进程执行的代码 */
     96     pid = getpid();  //取得 PID
     97     sleep(3);        //睡眠,让子进程先运行
     98     printf("This is parent process (pid = %d)\n", pid);
     99     
    100     for(i=1; i<NSIG; i++)
    101     {
    102         signal(i, parent);  //捕获所以信号
    103     }
    104     
    105     printf("Send SIGUSR1(%d) to CPID1 (%d)\n", SIGUSR1, cpid1);
    106     kill(cpid1, SIGUSR1);
    107     printf("Send SIGINT(%d) to CPID1 (%d)\n", SIGINT, cpid1);
    108     kill(cpid1, SIGINT);
    109     printf("Send SIGINT(%d) to CPID2 (%d)\n", SIGBUS, cpid2);
    110     kill(cpid2, SIGINT);
    111     printf("Send SIGUSR1(%d) to CPID2 (%d)\n", SIGUSR1, cpid2);
    112     kill(cpid2, SIGUSR1);
    113     
    114     for(; wait((int *)0) > 0; );  //等待子进程结束
    115     
    116     return 0;
    117 }

    在这个例程中,父进程又创建了两个子进程,这三个进程分别注册或忽略了相关的信号,然后通过 alarm 函数设置超

    时信号或通过 kill 函数发送信号。还用到了 pause 和 sleep 函数,如下:
     #include <unistd.h>
     int pause(void);
     unsigned int sleep(unsigned int seconds);

     pause 函数将使当前进程进入睡眠态,直到有信号发送。它的返回值永远是 -1,同时变量 errno 的值被设为

    EINTR 以表示有信号发生。
     sleep 函数将使当前进程进入睡眠态,并在 seconds 参数指定的秒数后被唤醒继续执行。注意当有未忽略的

    信号发生时 sleep 函数会提前返回,返回值是剩余的秒数。如果返回 0 则说明是正常被唤醒的,而不是因信号的发生

    提前返回的。

  • 相关阅读:
    新mac本安装Homebrew姿势(大前提:需要FQ)
    git 常用命令
    elementUI 函数自定义传参
    微信小程序避坑指南——echarts层级太高/层级遮挡
    前端向后端传递formData类型的二进制文件
    elemetnUI表格分别给列表每一个按钮加loading
    前端获取cookie,并解析cookie成JSON对象
    elementUI 输入框用户名和密码取消自动填充
    AOP面向切面编程
    关于ArrayList、HashSet、HashMap在并发下不安全的实例以及解决办法
  • 原文地址:https://www.cnblogs.com/wblyuyang/p/2767167.html
Copyright © 2020-2023  润新知