升级版信号处理函数sigaction/sigqueue

signal 函数的使用方法简单,但并不属于 POSIX 标准,在各类 UNIX 平台上的实现不尽相同,因此其用途受到了一定的限制。而 POSIX 标准定义的信号处理接口是 sigaction 函数,其接口头文件及原型如下:

#include <signal.h>

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

 ◆ signum:要操作的信号。
 ◆ act:要设置的对信号的新处理方式。
 ◆ oldact:原来对信号的处理方式。
 ◆ 返回值:0 表示成功,-1 表示有错误发生。

 struct sigaction 类型用来描述对信号的处理,定义如下:
 struct sigaction
 {
  void     (*sa_handler)(int);
  void     (*sa_sigaction)(int, siginfo_t *, void *);
  sigset_t  sa_mask;
  int       sa_flags;
  void     (*sa_restorer)(void);
 };

在这个结构体中,成员 sa_handler 是一个函数指针,其含义与 signal 函数中的信号处理函数类似。成员 sa_sigaction 则是另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。当 sa_flags 成员的值包含了 SA_SIGINFO 标志时,系统将使用 sa_sigaction 函数作为信号处理函数,否则使用 sa_handler 作为信号处理函数。在某些系统中,成员 sa_handler 与 sa_sigaction 被放在联合体中,因此使用时不要同时设置。

sa_mask成员用来指定在信号处理函数执行期间需要被屏蔽的信号,特别是当某个信号被处理时,它自身会被自动放入进程的信号掩码,因此在信号处理函数执行期间这个信号不会再度发生。

sa_flags 成员用于指定信号处理的行为,它可以是一下值的“按位或”组合。
 ◆ SA_RESTART:使被信号打断的系统调用自动重新发起。
 ◆ SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号。
 ◆ SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程。

 ◆ SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。
 ◆ SA_RESETHAND:信号处理之后重新设置为默认的处理方式。
 ◆ SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数。

 re_restorer 成员则是一个已经废弃的数据域,不要使用。

 下面用一个例程来说明 sigaction 函数的使用,代码如下:

 1 /*
 2  * 升级版信号操作函数sigaction/sigqueue
 3  * sigaction.c
 4  * Created on: Oct 30, 2016
 5  * Author: zhangming
 6  */
 7 #include <stdio.h>
 8 #include <string.h>
 9 #include <unistd.h>
10 #include <signal.h>
11 #include <errno.h>
12 
13 void deal(){
14     fprintf(stdout,"Begin deal...\n");
15     sleep(5); //deal things
16     fprintf(stdout,"End deal...\n");
17 }
18 
19 void handle(int s,siginfo_t* info,void *d){
20     if(s == SIGUSR1){
21         printf("SIGUSR1 %d received\n",info->si_int);
22         deal();
23     }else if(s== SIGUSR2){
24         printf("SIGUSR2 %d received\n",info->si_int);
25         deal();
26     }else{
27         printf("signal %d received\n",s);
28     }
29 }
30 
31 int main(int argc, char **argv) {
32     struct sigaction act;
33     memset(&act,'\0',sizeof(act));
34 
35     //包含了SA_SIGINFO 标志时,系统将使用sa_sigaction 函数作为信号处理函数,否则使用sa_handler作为信号处理
36     //用sigaction注册信号处理函数时,不会自动重新发起被信号打断的系统调用,如果需要自动重新发起,则要设置SA_RESTART标志
37     act.sa_sigaction = handle;
38     sigemptyset(&act.sa_mask); //注意:在添加屏蔽信号到屏蔽信号集之前,先清空信号集
39     //当信号处理中暂时屏蔽指定的SIGINT信号,退出信号处理函数后仍要执行SIGINT信号
40     sigaddset(&act.sa_mask,SIGINT);
41     //用sigaction注册信号处理函数时,不会自动重新发起被信号打断的系统调用。如果需要自动重新发起,则要设置SA_RESTART标志
42     //act.sa_flags = SA_SIGINFO | SA_RESTART;
43     act.sa_flags = SA_SIGINFO;
44 
45     sigaction(SIGUSR1,&act,NULL);
46     //sigaction(SIGUSR2,&act,NULL);
47 
48     char buf[512];
49     int r;
50     if(fork() == 0){ //child process
51         union sigval val;
52         val.sival_int=8888;
53         sigqueue(getppid(),SIGUSR1,val);
54         //sleep(1);
55         //sigqueue(getppid(),SIGUSR2,val);
56     }else{ //parent process
57         while(1){
58             if((r = read(STDIN_FILENO,buf,sizeof(buf))) == -1){
59                 if(errno == EINTR){ //EINTR: Interrupted system call
60                     printf("read is interrupted by signal\n");
61                 }
62             }else{
63                 buf[r-1] = '\0'; //去除一行的换行符
64                 printf("%d bytes read: %s\n", r, buf);
65             }
66         }
67     }
68 }

运行结果截图:

posted @ 2016-10-31 22:28  水火379  阅读(323)  评论(0)    收藏  举报