清单 8. 实际操作中的信号处理程序
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
void sighandler(int sig) {
printf("In signal handler for signal %dn", sig);
/* wait() is the key to acknowledging the SIGCHLD */
wait(0);
}
int main(void) {
int i;
/* Assign a signal handler to SIGCHLD */
sigset(SIGCHLD, &sighandler);
if (!fork()) {
/* Child */
_exit(0);
}
sleep(60);
}
sunbox$ gcc dIE3.c -o die3
sunbox$ ./die3 &
[1] 3116
sunbox$ In signal handler for signal 18
ps -ef | grep 3116
sean 3116 2885 0 22:37:26 pts/1 0:00 ./die3
由于使用了 sigset 函数(它向信号处理程序分配一个函数指针),清单 8 比前一个示例稍微复杂一点,。每当进程接收到某个已处理的信号时,就会调用通过 sigset 分配的函数。对于 SIGCHLD 信号,应用程序必须调用 wait(3c) 函数,以等待子进程退出。由于该进程已经退出,这相当于向内核确认了子进程的终止。实际上,父进程所做的工作可能不只是确认该信息。它还可能需要清理子进程的数据。
在执行 die3 以后,代码检查了进程清单,并干净地执行子进程。然后使用值 18 (SIGCHLD) 来调用信号处理程序,确认子进程的退出,并且父进程返回到 sleep(60)。
总结
Unix 进程是在某个进程调用 fork 时创建的,fork 将正在运行的可执行进程一分为二。然后该进程可以执行 exec 系列中的某个系统调用,从而将当前运行的映像替换为新的映像。
当父进程终止时,其所有子进程将由 PID 为 1 的 init 接纳。如果子进程在父进程之前终止,则会向父进程发送一个信号,然后子进程转变为僵死状态,直到该信号得到确认,或父进程被终止。
现在您已了解了进程是如何创建和销毁的,您已经为处理运行您系统的进程作了更好的准备,尤其是大量使用多进程的系统,例如 Apache。如果您需要执行某些故障排除,能够跟踪某个特定进程的进程树还允许您将任何应用程序追溯到创建它的进程。
标签: