一.什么是信号
信号是进程在运行过程中,由自身产生或进程外部发过来的消息(事件)。
信号是一种软件中断,它提供了一种处理异步事件的方法,也是进程间唯一的异步通信方式。在Linux系统中,不仅可以用来通知某种程序发生了什么事件,还可以给进程传递数据。
二.信号的种类
信号的名称是在头文件signal中定义的,信号都是以SIG开头。使用命令kill-l可以打印出信号列表。
编号为1~31的信号为不可靠信号(非实时信号),编号32~63的信号为可靠信号(实时信号)。不可靠信号和可靠信号的区别在于,不可靠信号不支持排队,可能会造成信号丢失,而可靠信号则不会。
三.信号处理函数
linux中有有两个常用的信号处理函数singnal和sigaction。有两个信号既不能被忽略也不能被捕捉,它们是SIGKILL和SIGSTOP。即进程接收到这两个信号后,只能接受系统的默认处理,即终止进程。
signal不支持信号传递信息,主要用于前32种非实时信号的处理。
signal函数声明如下
#include<signal.h>
typedefvoid (*sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);
第一个参数是指定要处理的信号。第二个参数是个函数指针,用来对指定信号的处理。参数可以为SIG_IGN(忽略该信号)SIG_DFL(系统默认处理)和自定义处理函数(函数原型必须为voidfunc(int))。
一个简单的例子来展示一下signal的用法。
运行结果如下
按下ctrl+c后会产生一个SIGINT信号,而该信号的默认操作是终止进程,但是在用signal函数后,更改对SIGINT信号的处理为我们的自定义函数。这个程序中按下ctrl+c无法终止进程,不过其他信号的处理没有改变,可以按下ctrl+ \ 结束进程。
sigcation函数声明如下
#include<signal.h>
intsigaction(int signum, const struct sigaction *act, structsigaction *oldact);
signal的第1个参数signum表示要捕捉的信号,第2个参数是个函数指针,表示要对该信号进行捕捉的函数,该参数也可以是SIG_DEF(表示交由系统缺省处理)或SIG_IGN(表示忽略掉该信号而不做任何处理)。signal如果调用成功,返回以前该信号的处理函数的地址,否则返回SIG_ERR。
sighandler_t是信号捕捉函数,由signal函数注册,注册以后,在整个进程运行过程中均有效,并且对不同的信号可以注册同一个信号捕捉函数。该函数只有一个参数,表示信号值。
sigaction函数原型
#include<signal.h>
intsigaction(int sig, const struct sigaction *act, struct sigaction*oldact);
结构体sigaction定义如下
struct sigaction{
void (*sa_handler)(int)
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flag;
void (*sa_restore)(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成员则是一个已经废弃的数据域,不要使用。
一个简单的例子来展示一下signal的用法。
运行结果
四.信号发送函数
(1)intraise(int sig); 对当前进程发送指定信号
(2)intpause(void);将进程挂起等待信号
(3)intkill(pid_t pid,int sig); 通过进程编号发送信号
(4)unsignedint alarm(unsigned int seconds); 指定时间(秒)发送SIGALRM信号。seconds为0时取消所有已设置的alarm请求;
(5)intsigqueue(pid_t pid,int sig,const union sigval val);类似于kill函数,多了附带共用体unionsigval形数,将共用体中的成员intsival_int或void*sival_ptr的值传递给信号处理函数中的定义类型siginfo_t中的intsi_int或void*si_ptr;
(6)intsetitimer(int which,const struct itimerval *value,struct itimerval*oldvalue); 可定时发送信号,根据which可指定三种信号类型:SIGALRM、SIGVTALRM和SIGPROF;作用时间也因which值不同而不同;structitimerval的成员it_interval定义间隔时间,it_value为0时,使计时器失效;
(7)voidabort(void)将造成进程终止;除非捕获SIGABORT信号;