一、信号的概念
信号时一种软件中断,很多应用程序应用的过程中都需要处理信号,也可以看作时进程与进程之间的一种通信方式。信号提供了一种处理异步事件的方法。
常见的Linux系统的系统信号是可以查的到的。
二、产生信号的条件
1、通过按终端键,来引发终端产生的信号。比如UNIX系统下的Crtl+c键可以用来中断一个进程。
2、硬件异常产生信号,比如除数为0,无效的内存引用等。
3、用户调用kill,killall命令来发送信号给其他进程。
4、进程调用kill、raise、alarm等函数来将任意信号发送给另一个进程或进程组。
5、检测到某种软件条件已经发生,比如SIGALRM(进程设置的定时器已经超时)。
三、信号的处理方式
1、忽略此信号
大都数的信号都是可以使用这种方式来进行处理的,但是有2种信号时不能被忽略的,分别是SIGKILL和SIGSTOP,因为它们向内核和超级用户提供了使进程结束和停止的可靠方法。
2、捕捉信号
这个需要通知内核在某种信号发生的时候,调用一个用户函数。在用户函数中,可执行用户希望对这种事件进行的处理。SIGKILL和SIGSTOP也是无法捕捉的。
3、执行系统默认的动作
对大多数的系统默认动作是终止该进程。还有一些是忽略和终止+core,这里的core文件是一种二进制文件,需要用一些高度工具才能解析。
ubuntu 默认不产生core文件,需要使用命令设置:
ulimit -c unlimited
四、信号集
多个信号的集合,数据类型是sigset_t,由128个二进制位组成,每个二进制代表的是一个信号,目前有大概64个信号。
int sigemptyset(sigset_t *set); //清空信号集 int sigfillset(sigset_t *set); //加满信号集 int sigaddset(sigset_t *set, int signum);//加一个信号到信号集 int sigdelset(sigset_t *set, int signum);//从信号集删除一个信号 int sigismember(const sigset_t *set, int signum);//从信号集中查找某个信号,成功返回1,失败返回0
每一个进程都有一个信号掩码,也就是一个信号集用来包含进程屏蔽的信号。
函数sigprocmask就是用来设置信号掩码的。
sigset_t set,oldset; // 初始化信号集 sigemptyset(&set); // 向信号集中添加信号 printf("向信号集中添加%d %s\n",34,sigaddset(&set,34)?"失败":"成功"); // 设置信号掩码 printf("设置信号掩码%s\n",sigprocmask(SIG_SETMASK,&set,&oldset)?"失败":"成功");
以下是修改信号掩码的方式:
SIG_BLOCK 向信号掩码当中添加信号
SIG_UNBLOCK 从信号掩码当中删除信号
SIG_SETMASK 用新的信号集替换旧的信号掩
五、信号的捕捉处理的函数
signal函数
1 #include<stdio.h> 2 #include<unistd.h> 3 #include<signal.h> 4 5 void sigsegv(int num) 6 { 7 printf("我捕获了一个信号%d\n",num); 8 exit(0); 9 } 10 int main() 11 { 12 signal(SIGSEGV,sigsegv); 13 int *p = NULL; 14 *p =100; 15 return 0; 16 }
通过这个函数,就可以捕捉到这个代码产生的段错误的信号,也就是SIGSEGV(11);
还有另外一个函数sigaction可以用来检查并修改指定信号相关联的处理动作
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
这个函数功能比较强大,同时也比signal复杂。