一、什么是信号
1、 信号就是软件中断,很多的程序都需要处理信号。信号提供了一种处理异步事件的机制。
例如:当用户在终端下运行一个程序时,用户在键盘键入一个中断键(CTRL+C),则会通过信号机制终止一个正在运行的程序。
2、每一个信号都有自己独特的名字。这些名字都是以SIG开头的。例如中断信号SIGINT.在linux下输入shell命令kill -l可以看到linux所支持的所有的信号名称以及信号的编号。其中1号到32号(32号信号用户是不能使用的)信号都是继承UNUX系统的信号。其余的是linux系统根据POSIX标注定义的信号。
3、在编写信号程序时,必须加上头文件<signal.h>。事实上,信号的定义的定义在另外的一个头文件中,但是该头文件又包含在<signal.h>中。
大家可以查看头文件/usr/include/signal.h 发现里边有一句include <bits/signum.h>,然后再查看头文件/usr/include/bits/signum.h 大家会发现信号的定义都在这里边.
二、信号产生的方式
1、用户按键,如用户按下了CTRL+C组合键
2、硬件异常,如除数为0,无效内存引用
3、进程调用kill函数将信号发送给一个进程或者进程组,限制条件是:接受信号进程和发送信号进程的所有者必须相同。或者发送信号的进程的所有者是超级用户
4、调用命令kill,实际上此命令是kill函数的接口
5、检测到某种软件条件已经发生。例如 SIGPIPE(管道的读进程已经终止后,另一个进程写此管道时产生)
当产生信号时,内核通常会在进程表中设置一个某种形式的标志,这就是所谓的向进程发送了一个信号。
三、进程的处理
1、捕捉信号,可以指定信号的处理函数,当捕捉的信号时自动执行此函数
2、忽略信号,除了SIGKILL和SIGSTOP,因为它们向超级用户提供了使进程终止或停止的方法。另外忽略了由某些硬件异常产生的信号(如无效内存引用),则进程运行的行为是不可预测的。
3、按照系统默认的方式处理,大部分信号的默认处理方式是终止进程,
四、信号的捕捉和处理
1、signal函数 -- 信号机制最简单的接口,用来设置进程在接受到信号时候的动作
在shell下输入man signal查看函数原型
#include <signal.h>
typedef void (*sighandler_t)(int); //定义函数指针类型
sighandler_t signal(int signum, sighandler_t handler);
signum为信号的编号
handler为信号处理函数
执行成功是返回信号处理函数指针,不成功时返回-1
举例如下:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
/*信号处理函数*/
void handler_signal(int signo)
{
printf("receive a signaln");
exit(0);
}
int main()
{
signal(SIGINT,handler_signal); //进程接收到中断信号(SIGINT),执行handler_signal函数
while(1);
return 0;
}
编译、运行程序
当用户按下CTRL+C组合键时,程序退出,输出receive a signal
这就是一个简单的关于信号的函数
2、sigaction函数
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
sigaction函数用来检查或者设置进程在接收到信号时的动作。
signum为信号编号
act不为空指针,则为新的信号处理函数;
oldact不为空指针,则为旧的信号处理函数将储存在oldact中。
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为信号处理函数的函数名
sa_sigaction也是信号处理函数的的函数名
sa_mask声明了一个信号集,在调用该信号捕捉函数之前,这一信号集要加入到进程的信号屏蔽字中。仅当从信号捕捉函数返回时再进行进程的信号屏蔽字复位。这样在调用信号处理程序时候就能阻塞某些信号。
sa_flags设置对信号处理的一些选项。
具体的sigaction结构体的介绍,在使用man手册中会又详细的介绍。
举个简单例子:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void signal_handler1(int sig)
{
printf("I am signal_handler1n");
printf("receive a signal!n");
exit(0);
}
void signal_handler2(int sig)
{
printf("I am signal_handler2n");
printf("receive a signal!n");
exit(0);
}
int main()
{
struct sigaction sac1,sac2;
sac1.sa_handler = signal_handler1;
sac2.sa_handler = signal_handler2;
sigaction(SIGINT,&sac1,NULL);//设置信号的处理函数,将信号SIGNAL和信号处理函数signal_handler联系起来
//sigaction(SIGINT,&sac2,NULL);//重新设置信号的处理函数,将信号SIGNAL和信号处理函数signal_handler2联系起来
while(1);
exit(0);
}