sigaction函数
sigaction函数的功能是用于改变进程接收到特定信号后的行为。
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
参数
--第一个参数是信号的值,可以为除了SIGKILL及SIGSTOP外的任何一个特定有效的信号(因为这两个信号定义了自己的处理函数,将导致信号安装错误)
--第二个参数是指向节后sigaction的一个实例的指针,在sigaction的实例中,指定了对特定信号的处理,可以为NULL,进程会以缺省方式对信号处理
--第三个参数oldact指向的对象用来保存原来对相应信号的处理,可以为NULL
返回值:函数成功返回0,失败返回-1。
sigaction函数检查或修改与指定信号相关联的处理动作,该函数取代了signal函数。
因为signal函数在信号未决时接收信号可能出现问题,所以使用sigaction更安全。
sigaction结构体
struct sigaction {
void (*sa_handler)(int);//信号处理程序 不接受额外数据
void (*sa_sigaction)(int, siginfo_t *, void *);//信号处理程序,能接受额外数据,可以和sigqueue配合使用
sigset_t sa_mask;
//sa_mask指定在信号处理程序执行过程中,哪些信号应当被阻塞。缺省情况下当前信号本身被阻塞,防止信号的嵌套发送,除非指定SA_NODEFER或者SA_NOMASK标志位。注:请注意sa_mask指定的信号阻塞的前提条件,是在由sigaction()安装信号的处理函数执行过程中由sa_mask指定的信号才被阻塞。
int sa_flags;//影响信号的行为SA_SIGINFO表示能接受数据
void (*sa_restorer)(void);//废弃
};
--第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中赢屏蔽掉哪些函数等等。
--回调函数sa_handler、sa_sigaction只能任选其一
/** @file signalT.cpp * @note * @brief * @author xor * @date 2019-7-20 * @history * @warning */ //捕捉信号 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <signal.h> void catch_signal(int sign) { switch(sign) { case SIGINT: //SIGINT默认行为是退出进程 printf("SIGINT signal "); exit(0); break; case SIGALRM: //SIGALRM默认行为是退出进程 printf("SIGALRM signal "); break; case SIGKILL: printf("SIGKILL signal "); break; } } //建议使用封装之后的mysignal int mysignal(int sign,void (*func)(int)) { struct sigaction act,oact; //传入回调函数 act.sa_handler=func; //将act的属性sa_mask设置一个初始值 sigemptyset(&act.sa_mask); act.sa_flags=0; return sigaction(sign,&act,&oact); } int main(int arg, char *args[]) { mysignal(SIGINT,catch_signal); mysignal(SIGALRM,catch_signal); mysignal(SIGKILL,catch_signal); int i=0; while(1) { printf("hello god %d ",i++); sleep(1); } return 0; }
sigqueue函数
--新的发送信号系统调用,主要是针对实时信号提出的支持信号带有参数,与sigaction()函数配合使用
--注意:和kill函数相比int kill(pid_t pid,int signo)多了参数
--原型 int sigqueue(pid_t pid,int signo,const union sigval value);
--参数 sigqueue的第一个参数是指定接收信号的进程pid,第二个参数确定即将发送的信号,
第三个参数是一个联合数据结构union sigval,指定了信号传递的参数,即通常所说的4字节值。
--函数成功返回0,失败返回-1,并且更新errno
--sigqueue()比kill()传递了更多的附加信息,但sigqueue()只能向一个进程发送信号,而不能发送信号给一个进程组
--union sigval联合体
typedef union sigval
{
int sival_int;
void * sival_ptr;
}sigval_t;
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/wait.h> #include <signal.h> /* siginfo_t { int si_signo; // Signal number int si_errno; // An errno value int si_code; // Signal code int si_trapno; // Trap number that caused hardware-generated signal (unused on most architectures) pid_t si_pid; // Sending process ID uid_t si_uid; // Real user ID of sending process int si_status; // Exit value or signal clock_t si_utime; // User time consumed clock_t si_stime; // System time consumed sigval_t si_value; // Signal value int si_int; // POSIX.1b signal void *si_ptr; // POSIX.1b signal int si_overrun; // Timer overrun count; POSIX.1b timers int si_timerid; // Timer ID; POSIX.1b timers void *si_addr; // Memory location which caused fault int si_band; // Band event int si_fd; // File descriptor } */ void catch_signal(int signo,siginfo_t *resdata,void *unkonwp) { printf("signo=%d ",signo); printf("return data :%d ",resdata->si_value.sival_int); printf("second return data:%d ",resdata->si_int); return ; } int main(int arg, char *args[]) { pid_t pid=0; pid=fork(); if(pid==-1) { printf("fork() failed! error message:%s ",strerror(errno)); return -1; } if(pid==0) { printf("i am child! "); //等待父进程执行完信号安装 sleep(5); //向父进程发送带数据的信号 union sigval sigvalue; sigvalue.sival_int=222; //发送信号 if(sigqueue(getppid(),SIGINT,sigvalue)==-1) { printf("sigqueue() failed ! error message:%s ",strerror(errno)); exit(0); } printf("子进程信号发送成功! "); exit(0); } if(pid>0) { printf("i am father! "); //安装信号 struct sigaction act; //初始化sa_mask sigemptyset(&act.sa_mask); act.sa_sigaction=catch_signal; //一旦使用了sa_sigaction属性,那么必须设置sa_flags属性的值为SA_SIGINFO act.sa_flags=SA_SIGINFO; //安装信号 if(sigaction(SIGINT,&act,NULL)!=0) { printf("sigaction() failed! "); return -1; } //等待子进程返回 int status=0; wait(&status); printf("game over! "); } return 0; }
实时信号支持排队不会丢失。(实时信号还有一个特点,即到达的顺序是可以保证的)