Linux下信号的概念及相关函数
1.基本概念
-
信号的共性
- 简单
- 不能携带大量信息
- 满足某个特定条件才发送
-
信号的特质
- 信号是软件层面上的中断,一旦信号产生,无论程序执行到什么位置,必须停止运行来处理信号,处理结束后才能执行别的指令
- 所有信号的产生和处理都是由内核完成的
-
与信号相关的事件和状态
-
产生信号
- 按键产生,如:Ctrl+c、Ctrl+z、Ctrl+\
- 系统调用产生,如:kill、raise、abort
- 软件条件产生,如:定时器alarm
- 硬件异常产生,如:非法访问内存(段错误)、除0(浮点数除外)、内存对齐出错(总线错误)
- 命令产生,如:kill命令
-
信号的处理方式
- 执行默认操作
- 忽略(丢弃)
- 捕捉(调用户处理函数)
-
递达与未决
- 递达:产生并且送达到进程,直接被内核处理掉
- 未决:产生与递达之间的状态
-
未决信号集和阻塞信号集
- 未决信号集:
- 信号产生,未决信号集中描述该信号的位立刻翻转位1,表示该信号处于未决状态。当信号被处理时对应位翻转回0,这一时刻往往非常短暂。
- 信号产生后由于某些原因(主要为阻塞)不能抵达。这类信号的集合称为未决信号集。屏蔽解除前,信号一直处于未决状态。
- 阻塞信号集(信号屏蔽字):将某些信号写入集合,对他们设置屏蔽。当屏蔽某信号后,再次收到这个信号,该信号的处理将推后。
- 两者的本质都是位图。
- 未决信号集:
-
-
信号四要素
- 编号
- 名称
- 事件
- 默认处理动作
2.常用的信号
-
SIGHUP(1):当进程退出shell时,由该shell启动的所有进程将收到这个信号,默认动作终止进程
-
SIGINT(2):当用户按下Ctrl+C组合键的时候,用户终端向正在进行中的由该终端启动的程序发出这个信号,默认动作为终止进程
-
SIGQUIT(3):当用户按下Ctrl+\组合键的时候产生该信号,用户终端向正在运行中由该终端启动的程序发出的信号,默认动作为终止进程
-
SIGBUS(7):非法访问内存地址,包括内存对齐出错,默认动作为终止进程并且产生core文件
-
SIGFPE(8):在发生致命的运算错误时发出。不仅包括浮点运算错误,还包括溢出和除数等于0等所有的算法错误,默认动作为终止进程并且产生core文件
-
SIGKILL(9):无条件终止进程。本信号不能被忽略、处理和阻塞。默认动作为终止进程。它向系统管理员提供了杀死任何进程的方法。
-
SIGUSR1(10):用户定义的信号,即程序员可以在程序中定义并使用该信号,默认动作为终止进程
-
SIGSEGV(11):指示进程进行了无效内存访问。默认动作为终止进程并且产生core文件
-
SIGUSR2(12):用户定义的信号,即程序员可以在程序中定义并使用该信号,默认动作为终止进程
-
SIGPIPE(13):Broken pipe向一个没有读端的管道写数据。默认动作为终止进程
-
SIGALRM(14):定时器超时,超时的时间由系统调用alarm设置,默认为终止进程
-
SIGTERM(15):程序结束信号,与SIGKILL不同在于该信号可以被阻塞和终止。通常用于指示程序正常退出,执行shell命令kill时,缺省产生这个信号,默认动作为停止进程
-
SIGCHLD(17):子进程状态发生变化时,父进程会收到这个信号,默认为忽略这个信号
-
SIGSTOP(19):停止进程的执行,该信号不能被忽略、处理和阻塞,默认动作为暂停进程
3.软件条件产生信号
-
alarm函数
-
原型
unsigned int alarm(unsigned int seconds);
-
作用:定时给自己发SIGALRM信号
-
返回值:
0或者剩余的秒数
-
参数:
seconds:定时秒数
-
time指令:查看程序的执行时间,实际时间=用户时间+内核时间+等待时间
-
-
setitimer函数
-
原型
int setitimer(int which, const struct itimerval* new_value, struct itimerval* old_value);
-
参数:
which:指定定时方式
-
自然定时:ITIMER_REAL→14)SIGALRM
计算自然时间
-
虚拟空间计时(用户空间):ITIMER_VIRTUAL→26)SIGVTALRM
计算进程占用CPU的时间
-
运行时计时(用户+内核):ITMER_PROF→27)SIGPROF
计算占用CPU以及执行系统调用的时间
new_value:定时时间
-
类型:
struct itimerval{ struct timeval it_interval; //设定两次定时器的间隔时间 struct timeval it_value; //定时的时长 } struct timeval{ time_t tv_sec; suseconds_t tv_usec; }
old_value:传出参数,上次定时剩余时间
-
-
返回值
成功:0
失败:-1,设置errno
-
4.kill函数/命令产生信号
-
kill命令
kill + - +信号编号 + 进程号
-
kill函数
-
原型:
int kill(pid_t pid, int sig);
-
参数:
pid:
1. > 0 发送信号给指定的进程
2. = 0 发送给于kill函数进程属于同一个进程组的所有进程
3. < -1 取|pid|发送给对应的进程组
4. = -1 发送给进程有权限发送的系统中的所有进程
int:信号编号
-
返回值:
成功:0
失败:-1,设置errno
-
5.信号集操作函数
sigset_t set; //自定义信号集
int sigemptyset(sigset_t* set); //清空信号集
int sigfillset(sigset_t* set); //将信号集全部置1
int sigaddset(sigset_t* set, int signum); //将一个信号添加到集合中
int sigdelset(sigset_t* set, int signum); //将一个信号从集合中删除
//判断一个信号是否在集合里
int sigismember(const sigset_t* set, int signum);
-
设置信号屏蔽字和解除屏蔽
-
原型
int sigprocmask(int how, const sigset_t* set, sigset_t* oldset);
-
参数:
how:
-
SIG_BLOCK 设置阻塞
-
SIG_UNBLOCK 取消阻塞
-
SIG_SETMASK 用自定义的set替换mask
set:自定义的set
oldset:旧的mask,传出参数
-
-
-
查看未决信号集
-
原型
int sigpending(sigset_t* set);
-
参数
set:传出的未决信号集
-
6.信号捕捉
-
signal函数
-
原型
sighandler_t signal(int signum, sighandler_t handler);
-
参数:
signum:信号的编号
handle:信号的处理函函数,只能为返回值空参数int的函数
-
typedef void (*sighandler_t)(int);
-
-
返回值:
成功:返回旧的处理函数指针
失败:SIG_ERR,设置errno
-
-
sigaction函数
-
原型:
int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact);
-
参数:
signum:信号的编号
sigaction:存放信号动作的结构体
-
struct sigaction{ //信号处理函数 void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t* ,void*); sigset_t sa_mask; //信号处理函数里维护的屏蔽信号集 int sa_flags; //设置默认属性 void (*sa_restorer)(void); }
-
-
-
注意事项:
- 捕捉函数执行期间,信号屏蔽字由mask→sa_mask,捕捉函数结束后回复为mask
- 捕捉函数执行期间,本信号会被自动屏蔽(sa_flag = 0)
- 捕捉函数执行期间,被屏蔽信号多次发送,解除屏蔽后只处理一次
7.SIGCHLD信号
-
信号的产生条件
- 子进程终止时
- 子进程接收到SIGSTOP信号停止时
- 子进程处在停止态,接收到SIGCONT后唤醒时
-
作用:可以用于回收子进程