文章目录
信号是由用户、系统或进程发送给目标进程的信息,以通知目标进程某个状态的改变或者系统异常。
Linux的信号可由如下条件产生:
- 用户可以通过输入特殊的终端字符给前台进程发送信号,如
Ctrl + C
发送中断信号。 - 系统异常。比如浮点异常和非法内存段访问
- 系统状态变化。比如alarm定时器到期引起的
SIGALRM
信号 - 运行
kill
命令或者调用kill
函数
服务器应该及时处理或忽略常见信号,以避免异常终止。
Linux信号概述
发送信号
#include<sys/types.h>
#include<signal.h>
int kill(pid_t pid, int sig);
该函数将信号sig
发送给目标进程,目标进程由pid指定
sig是信号值,如果设置为0,则不发送任何信号。但将其设置为0可以检测目标进程或进程组是否存在,因为会在信号发送前执行检查操作。但是这种方法并不可靠:①进程的PID回绕,导致被检测的PID不是期望的PID。②这种检测方法不是原子性的
执行成功返回0,失败返回-1,常见的errno值:
- EINVAL 无效信号
- EPERM 该进程没有权限发送信号给其他进程
- ESRCH 目标进程或进程组不存在
信号处理方式
#include<signal.h>
// 函数原型
typedef void (*__sighandler_t) (int);
#include<bits/signum.h>
#define SIG_DFL ((__sighandler_t) 0)
#define SIG_IGN ((__sighandler_t) 1)
信号处理函数只有一个带整形参数来指示信号类型。信号处理函数应该是可重入的,以避免竞态条件,所以在信号处理函数中禁用不安全代码。
除了用户自定义信号处理函数,还有两个宏(如上所示)SIG_IGN
表示忽略该信号,SIG_DFL
表示使用信号的默认处理方式——结束进程(Term)、忽略信号(Ign),结束进程并生成核心转储文件(Core),暂停进程(Stop),继续进程(Cont)
Linux信号
定义在bits/signum.h
中,常用的信号:SIGHUP
, SIGPIPE
, SIGURG
, SIGALRM
, SIGCHLD
。
中断系统调用
信号函数
signal
signal系统调用可以为一个信号设置处理函数
#include<signal.h>
_sighandler_t signal (int sig, _sighandler_t _handler);
·sig参数指定要捕获的信号类型,_handler参数是_sighandler_t 类型的函数指针,用于指定信号sig的处理函数。
signal调用成功时返回一个函数指针,是前一次调用signal函数时传入的函数指针或者是信号sig对应的默认处理函数指针SIG_DEF(如果是第一次调用signal的话)。
调用失败则返回SIG_ERR
sigaction
设置信号处理函数更健壮的接口是如下的系统调用
#include<signal.h>
int sigaction(int sig, const struct sigaction* act, struct sigaction* oact);
sig参数指定信号类型,act参数指定新的信号处理方式,oact输出信号之前的处理方式。
struct sigaction{
#ifdef __USE_POSIX199309
union
{
// 指定信号处理函数
__sighandler_t sa_handler;
void (*sa_sigaction) (int