进程与信号
本节以父进程与子进程通信为例介绍信号的使用。
子进程的终止属于异步事件,父进程无法预知其子进程何时终止,父进程可调用 wait 函数来防止僵尸进程的累积,通常父进程可以用以下两种方法:
- 父进程调用不带 WNOHANG 标志的 wait 函数或 waitpid 函数,如果尚无已经终止的子进程,那么调用将会阻塞。
- 父进程周期性地调用带有 WNOHANG 标志的 waitpid 函数,针对指定的子进程进行非阻塞式检查。
对于第一种方法,有时可能并不希望父进程以阻塞的方式来等待子进程的终止,而第二种方法反复以轮询的方式会造成 CPU 资源的浪费,并增加应用程序设计的复杂度。因此,为了规避这些问题,可以采用针对 SIGCHLD 信号的处理程序。
无论子进程何时终止,都会向父进程发送 SIGCHLD 信号(这是 SylixOS 的默认情况),SylixOS 对该信号的默认处理,有两种情况,一种是默认忽略,另一种是如果设置 sigaction 的 sa_flags 标志包含 SA_NOCLDWAIT,则系统自动回收子进程资源(这将由系统线程“t_recliam”进行回收)。应用程序也可以安装信号处理函数来捕获 SIGCHLD 信号,在信号处理函数中进行子进程资源的回收工作。
前面我们介绍过,除了 SI_KILL(kill 函数发送)类型信号,所有其他类型的信号都是可排队的,因此,我们可以得知,即使在安装 SIGCHLD 信号时没有指定 SA_NOMASK 标志,子进程发送的 SIGCHLD 信号也不会丢失,因为此信号将会排队。
如果要安装 SIGCHLD 信号处理函数,程序实现中不得不考虑可重入性问题,例如:在信号处理函数中调用系统函数,可能会改变全局变量 errno 的值。存在这样的情况,当信号处理函数企图显式地设置 errno 值或者系统函数返回失败时检查 errno 值时,将可能出现冲突,因此,通常在编写信号处理函数时,首先用局部变量来保存 errno 值,最后将其恢复。
正如前面所述,当子进程退出时就会发送 SIGCHLD 信号给父进程,但是,如果在调用 sigaction 函数时指定了 SA_NOCLDSTOP 标志将禁止子进程发送 SIGCHLD 信号。需要注意的是,SA_NOCLDSTOP 标志只对 SIGCHLD 信号有作用。在 SylixOS 中,当信号 SIGCONT 导致已停止的子进程恢复执行时,会向其父进程发送 SIGCHLD 信号,这是 SUSv3 中允许的特性。