升级版信号处理函数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 }
运行结果截图:


浙公网安备 33010602011771号