信号编程之sigaction函数和sigqueue函数
来源:互联网 发布:2016nba常规赛数据 编辑:程序博客网 时间:2024/06/01 17:05
函数介绍
- 包含头文件
<signal.h>
- 功能:sigaction函数用于改变进程接收到特定信号后的行为。
- 原型:
int sigaction(int signum,const struct sigaction *act,const struct sigaction *old);
- 参数
- 该函数的第一个参数为信号的值,可以为除SIGKILL及SIGSTOP外的任何一 个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)
- 第二个参数是指向结构sigaction的一个实例的指针,在结构 sigaction的实例中,指定了对特定信号的处理,可以为空,进程会以缺省方式对信号处理
- 第三个参数oldact指向的对象用来保存原来对相应信号的处理,可指定oldact为NULL。
- 返回值:函数成功返回0,失败返回-1
关于sigaction结构体
其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等
struct sigaction { void (*sa_handler)(int); //信号处理程序 不接受额外数据 void (*sa_sigaction)(int, siginfo_t *, void *); //信号处理程序 能接受额外数据,和sigqueue配合使用 sigset_t sa_mask; // int sa_flags; //影响信号的行为 SA_SIGINFO表示能接受数据 void (*sa_restorer)(void); //废弃};
注意:回调函数句柄sa_handler、sa_sigaction只能任选其一。
- 补充siginfo_t 结构体介绍
siginfo_t { int si_signo; /* Signal number */ int si_errno; /* An errno value */ int si_code; /* Signal code */ 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 */ void * si_addr; /* Memory location which caused fault */ int si_band; /* Band event */ int si_fd; /* File descriptor */ }
示例代码
- 最基本的用法
void handler(int sig){ if (sig == SIGINT) { printf("recv a sig=%d\n", sig); }}int main(){ struct sigaction act; act.sa_handler = handler; sigaction(SIGINT,&act,NULL); while(1); return 0;}
- 利用sigaction实现my_signal
#include <unistd.h>#include <sys/stat.h>#include <sys/wait.h>#include <sys/types.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <signal.h>void handler(int sig){ printf("Aloha recv a sig=%d\n", sig); }/*打造一个和signal功能一样的函数*/__sighandler_t my_signal(int sig, __sighandler_t handler){ struct sigaction act; struct sigaction oldact; /*在使用一个sigaction结构体之前,需要先对以下三个成员进行处理*/ act.sa_handler = handler;//指定新的处理函数 sigemptyset(&act.sa_mask);//设置信号屏蔽字 act.sa_flags = 0; if (sigaction(sig, &act, &oldact) < 0)//注册信号,指定信号处理函数的同时备份之前的信号处理信息(包括之前该信号的处理函数) return SIG_ERR;//注册失败--返回SID_ERR return oldact.sa_handler;//注册成功--返回之前的信号处理函数}int main(int argc, char *argv[]){ //模拟signal函数 my_signal(SIGINT, handler); for (;;) { pause(); } return 0;}
sigqueue函数
功能:新的发送信号系统调用,主要是针对实时信号提出的支持信号带有参数,与函数sigaction()配合使用。
注意:和kill函数相比
int kill(pid_t pid, int siq)
多了参数原型:
int sigqueue(pid_t pid, int sig, const union sigval value);
- 参数
sigqueue的第1个参数是指定接收信号的进程id,第2个参数确定即将发送的信号,第3个参数是一个联合数据结构union sigval,指定了信号传递的参数,即通常所说的4字节值。 - 返回值成功返回0,失败返回-1
sigqueue()比kill()传递了更多的附加信息,但sigqueue()只能向一个进程发送信号,而不能发送信号给一个进程组。
- sigval联合体
typedef union sigval { int sival_int; void *sival_ptr; }sigval_t;
注意:
(1) 如果要让信号处理函数能够接收额外的数据,需要配合sigaction结构体中的sa_flags成员, SA_SIGINFO表示能接受数据。
(2) 信号处理函数的原型要使用void myHandle_forsigaction(int signum, siginfo_t *s_t, void *p)
,这个函数实在内核空间被调用的,所以形参也是在内核空间,同时,接收到的额外数据就放在siginfo_t 结构体的如下成员里。si_value和si_int是为了兼容性设置的,两个内容相同。si_ptr则对应额外数据结构体里面的void*指针部分。上述两个部分,在内核发送信号的时候,只能发送其中一部分,因为额外数据是一个union类型。
sigval_t si_value;int si_int; /* POSIX.1b signal */void * si_ptr; /* POSIX.1b signal */
- 示例代码
#include <unistd.h>#include <sys/stat.h>#include <sys/wait.h>#include <sys/types.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <signal.h>void handler(int sig,siginfo_t *s_t,void *p)//能够接受额外数据的信号处理函数签名{ int tmp = 0; tmp = s_t->si_int; //si_int和si_value.sival_int是一样的--针对额外数据是int的时候。 printf("Aloha recv a sig=%d\tvar :%d\n and var is also: %d", sig,tmp,s_t->si_value.sival_int); }int main(int argc, char *argv[]){ pid_t pid; int ret = 0; int i = 0; union sigval mysigval;//用来存放额外数据 struct sigaction act;//用来注册信号 /*使用sigaction必须要初始化的三个成员*/ act.sa_sigaction = handler;//指定回调函数 act.sa_flags = SA_SIGINFO;//尤其重要--只有等于SA_SIGINFO,信号处理函数才能接受额外数据 sigemptyset(&act.sa_mask);//清空屏蔽字 if(sigaction(SIGINT,&act,NULL) < 0)//注册信号--指定毁掉函数 { perror("sigaction error!\n"); exit(-1); } pid = fork();//创建子进程 if(-1 == pid) { perror("fork"); exit(-1); } else if(0 == pid) { mysigval.sival_int = 125;//设置要随着信号发送的额外数据 for(i = 0;i < 10;i++)//子进程发送十次信号--SIGINT是不可靠信号--传送有点慢 { ret = sigqueue(getppid(),SIGINT,mysigval);//开始发送信号 if(ret != 0)//发送失败 { perror("sigqueue"); exit(-1); } else{//返回0表示信号发送成功 printf("send ok!\n"); sleep(1); } } } else if(pid > 0) { while(1);//父进程死循环 } return 0;}
可靠信号和不可靠信号的区别及测试
- 可靠信号在遇到阻塞的时候需要缓存,所以缓冲区有上限,也就是发送可靠信号的数量是有限的,可用ulimit -a命令查看。
- 可靠信号会在解除阻塞以后全部抵达,但是不可靠信号只有最后一个会抵达!
#include <unistd.h>#include <sys/stat.h>#include <sys/wait.h>#include <sys/types.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <signal.h>/*TEST_SIG_LIMIT如果定义为1表示进行压力测试如果定义位0表示进行可靠信号和不可靠信号的区别测试*/#define TEST_SIG_LIMIT 0#if (TEST_SIG_LIMIT==1)#define MAX 1024#else#define MAX 1#endifvoid handler(int sig,siginfo_t *s_t,void *p)//能够接受额外数据的信号处理函数签名{ int tmp = 0; sigset_t bset; if(sig == SIGINT || sig == SIGRTMIN) { tmp = s_t->si_int; //si_int和si_value.sival_int是一样的--针对额外数据是int的时候。 printf("Aloha recv a sig=%d\tvar :%d\t and var is also: %d\n", sig,tmp,s_t->si_value.sival_int); } else if(sig == SIGUSR1) { printf("unblock\n"); /*阻塞实时信号和非实时信号*/ sigemptyset(&bset); sigaddset(&bset,SIGINT); sigaddset(&bset,SIGRTMIN); sigprocmask(SIG_UNBLOCK,&bset,NULL); } else { printf("other signal\n"); }}void my_handler(int sig){ sigset_t bset; if(sig == SIGINT || sig == SIGRTMIN) { printf("The sig num is : %d\n",sig); } else if(sig == SIGUSR1) { printf("unblock\n"); /*阻塞实时信号和非实时信号*/ sigemptyset(&bset); sigaddset(&bset,SIGINT); sigaddset(&bset,SIGRTMIN); sigprocmask(SIG_UNBLOCK,&bset,NULL); } else { printf("other signal\n"); }}int main(int argc, char *argv[]){ pid_t pid; int ret = 0; int i = 0; struct sigaction act;//用来注册信号 sigset_t bset; union sigval v; /*使用sigaction必须要初始化的三个成员*/ //act.sa_handler = my_handler;//指定回调函数 act.sa_sigaction = handler; act.sa_flags = SA_SIGINFO;//尤其重要--只有等于SA_SIGINFO,信号处理函数才能接受额外数据 sigemptyset(&act.sa_mask);//清空屏蔽字 if(sigaction(SIGINT,&act,NULL) < 0)//注册非实时信号 { perror("sigaction error!\n"); exit(-1); } if(sigaction(SIGRTMIN,&act,NULL) < 0)//注册实时信号 { perror("sigaction error!\n"); exit(-1); } if(sigaction(SIGUSR1,&act,NULL) < 0)//注册用户自定义信号SIGUSR1 { perror("sigaction error!\n"); exit(-1); } /*阻塞实时信号和非实时信号*/ sigemptyset(&bset); sigaddset(&bset,SIGINT); sigaddset(&bset,SIGRTMIN); sigprocmask(SIG_BLOCK,&bset,NULL); pid = fork();//创建子进程 if(-1 == pid) { perror("fork"); exit(-1); } else if(0 == pid) { v.sival_int = 0; for(i = 1;i < MAX*1024;i++)//发送三次不可靠信号 { v.sival_int++; ret = sigqueue(getppid(),SIGINT,v); if(ret != 0) { printf("sigqueue SIGINT failed!..ret=%d\terrno=%d\tindex=%d\n",ret,errno,i);//不可靠信号不用缓存--无限制--不会出错/不会执行! exit(-1); } else{ if(i % (1024*512) == 0) printf("send SIGINT OK!--index:%d\n",i); } } v.sival_int = 0; for(i = 1;i < MAX*1024;i++)//发送三次可靠信号 { v.sival_int++; ret = sigqueue(getppid(),SIGRTMIN,v); if(ret != 0) { printf("sigqueue SIGRTMIN failed!..ret=%d\terrno=%d\tindex=%d\n",ret,errno,i);//可靠信号需要缓存--所以有限制--ulimit -a命令查看--此时index即上限 exit(-1); } else{ if(i % 512 == 0) printf("send OK!--index:%d\n",i); } } ret = kill(getppid(),SIGUSR1);//发送自定义信号--解除阻塞 if(ret == -1) { printf("sigqueue failed!..%d\t%d\n",ret,errno); exit(-1); } else if(ret == 0){ printf("send OK!\n"); } } else if(pid > 0) { while(1);//父进程死循环 } return 0;}
0 0
- 信号编程之sigaction函数和sigqueue函数
- linux系统编程之信号(六):信号发送函数sigqueue和信号安装函数sigaction
- linux系统编程之信号(六):信号发送函数sigqueue和信号安装函数sigaction
- linux系统编程之信号(六):信号发送函数sigqueue和信号安装函数sigaction
- 信号发送函数sigqueue和信号安装函数sigaction
- 信号发送函数sigqueue和信号安装函数sigaction
- 信号发送函数sigqueue和信号安装函数sigaction
- 信号发送函数sigqueue和信号安装函数sigaction
- linux信号捕捉和sigaction函数和sigqueue函数
- linux 信号发送函数sigqueue和信号安装函数sigaction用法
- linux 信号的捕捉和发送函数的简单使用:sigaction()和sigqueue()
- 十八、Linux系统编程-信号(五)sigaction和sigqueue
- 信号相关函数(signal,sigaction,sigprocmask, kill,sigqueue信号发送函数,睡眠函数,计时器函数)
- 信号发送(sigqueue)和接收(sigaction)
- linux系统编程之信号(五):实时信号与sigqueue函数
- linux系统编程之信号(五):实时信号与sigqueue函数
- linux之信号处理函数signal和sigaction
- sigaction和sigqueue
- 单例设计模式
- android初级学习之视图的绘制(自定义View的实现原理)
- /proc/modules, /proc/devices, /dev
- 学呼—在线管理系统实现及源码struts2+Hibernatex项目
- [Data Structure & Algorithm] 七大查找算法
- 信号编程之sigaction函数和sigqueue函数
- 解决问题
- leetcode61
- 学习进程01 - 总结归纳【读取文件的方法】以及【字符串操作】
- 算法模版 辗转相除
- MSP430F5438A中断系统
- PMAC 误差补偿的方法及步骤
- AndroidStudio的快捷键大全
- Android ---ListView 的初体验