wblyuyang

博客园 首页 新随笔 联系 订阅 管理

捕捉信号:
  
 
使用 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 则说明是正常被唤醒的,而不是因信号的发生

提前返回的。

posted on 2012-11-12 22:42  wblyuyang  阅读(1514)  评论(0编辑  收藏  举报