20.1 概念和概述
信号是事件发生时对进程的通知机制
一颗进程可以向另一进程发送信号,信号的这一用法可作为一种同步技术。
然而,发往进程的诸多信号,通常都是源于内核。
引发内核为进程产生信号的各类事件如下:
- 硬件异常(被零除,访问位未知空间)
- 用户键入特殊字符(ctrl+c/v)
- 发生软发事件(针对某个文件描述符的输出变为有效,调整了终端窗口大小,定时器到期,等)
每个信号被定义成一个整数,<signal.h>中以SIGxxxx形式的符号名对这些整数做了定义。
信号被分为两大类。第一组用于内核向进程通知事件,构成所谓传统或者标准信号。范围为1-31。另一组由实时信号构成。
有时需要确保一段代码不被信号干扰,可以将信号添加到进程的信号掩码中,会阻塞该组信号的到达。
20.2 信号类型和默认行为
20.3 改变信号处置:signal()
UNIX系统提供了两种方法: signal()和sigaction().后者提供了更多功能。前者可移植性不强。
下列代码可以暂时为信号建立一个处理器函数,然后再将信号处置重置为其本来面目。
使用signal(),将无法在不改变信号处置的同时,还能获取到当前的信号处置。要想做到这一点,必须使用sigaction().
在为signal指定handler时,可以用如下值代替:
- SIG_DFL 将信号处置重置为默认值
- SIG_IGN 忽略该信号。
20.4 信号处理器简介
信号处理器程序是当指定信号传递给进程时将会调用的一个函数。
用法:
20.5 发送信号 kill()
如果pid=0,那么会发送信号给与调用进程同组的每个进程,包括自身。
如果pid<-1, 那么会发送给该PID绝对值的进程组内所有下属进程发送信号。
如果pid=-1, 那么发送给所有进程,除了INIT和自身。
若无此进程,则调用失败,errno置为ESRCH。
20.6 检查进程的存在
kill()系统调用还有另一重功用,若将参数置为0,则无信号发送。以此检测进程的存在。
其他检查进程存在的技术:
- wait()
- 信号量和排他文件锁
- 管道和FIFO之类的IPC通道
- /proc/PID接口
20.7 发送信号的其他方式:raise()和killpg()
向自身发送信号。错误返回非零。唯一错误为SIG无效(EINVAL)
killgp()向某一进程组的所有进程发送一个信号
20.8 显示信号描述
每个信号都有一串与之相关的可打印说明。这些描述位于数组sys_siglist中。
可以用sys_siglist[SIGPIPE]来获取对SIGPIPE信号的描述。
推荐使用strsignal()函数。
该函数可以对SIG进行边界检查。
20.9 信号集
多个信号可以使用一个称之为信号集的数据结构来表示,其系统数据类型为sigset_t.
sigemptyset初始化一个未包含任何成员的信号集。
sigfillset初始化一个包含所有信号的信号集(全家桶???)
这两个简单
sigismember测试SIG是否属于该信号集
上述三个为GUNC库非标准函数
20.10 信号掩码
内核会为每个进程维护一个信号掩码,即一组信号,并将阻塞其针对该进程的传递。
会阻塞至从进程信号掩码中移除为止。
向信号掩码中添加信号的方式:
这里介绍sigprocmask()
sigprocmask函数既可以修改进程的信号掩码,又可以获取现有掩码,或者两重功效兼具。
how:指定了该函数想给信号掩码带来的变化。
若oldset不为空,则其指向一个sigset_t结构缓冲区,用于返回之前的信号掩码。
若只想获取信号掩码,可将set置空。
20.11 处于等待状态的信号
可以使用sigpending函数获取调用进程处于等待状态的信号集。
20.12 不对信号进行排队处理
没看懂它到底想表达什么??
20.13 改变信号处置 :sigaction()
sigaction()的用法比signal()更加复杂也更加灵活。且移植性更佳。
sig : 标识信号编号,(除SIGKILL和SIGSTOP)
act:指向描述信号新处置的数据结构。如下
oldact:获取old 处置指针
sigaction的结构:
- sa_handler: 新处理函数,可以为SIG_IGN和SIG_DFL.
- sa_mask: 信号组,在调用sa_handler所定义的处理器程序时将阻塞该组信号。(应该只是暂时性阻塞)
- sd_flags:指定用于控制信号处理过程的各种选项的位掩码:
20.14 等待信号: pause()
pause()将暂停信号的执行,直至信号处理器函数中断该调用为止。
(不知道它这怎么中断该调用)