信号处理的一个典型应用。
自动清除子进程,防止僵尸进程
异步清理子进程
如果您创建一个子进程只是简单的调用 exec 运行其它程序,在父进程中立刻调用 wait
进行等待并没有什么问题,只是会导致父进程阻塞等待子进程结束。但是,很多时候您希望在子进程运行的同时,父进程继续并行运行。怎么才能保证能清理已经结
束运行的子进程而不留下任何僵尸进程在系统中浪费资源呢?
一种解决方法是让父进程定期调用 wait3 或 wait4 以清理僵尸子进程。在这种情况调用 wait
并不合适,因为如果没有子进程结束,这个调用会阻塞直到子进程结束为止。然而,您可以传递 WNOHANG 标志给 wait3 或 wait4
函数作为一个额外的参数。如果设定了这个标志,这两个函数将会以非阻塞模式运行——如果有结束的子进程,它们会进行清理;否则会立刻返回。第一种情况下返
回值是结束的子进程ID,否则返回0。
另一种更漂亮的解决方法是当一个子进程结束的时候通知父进程。有很多途径可以做到这一点;“进程间通信”介绍了这些方法,不过幸运的是Linux
利用信号机制替您完成了这些。当一个子进程结束的时候,Linux 给父进程发送 SIGCHLD
信号。这个信号的默认处理方式是什么都不做;这也许是为什么之前您忽略了它的原因。
因此,一个简单的清理结束运行的子进程的方法是响应 SIGCHLD
信号。当然,当清理子进程的时候,如果需要相关信息,一个很重要的工作就是保存进程退出状态,因为一旦用 wait
清理了进程,就再也无法得到这些信息了。代码中就是一个利用 SIGCHLD 信号处理函数清理子进程的程序代码
- #include <signal.h>
-
#include <string.h>
-
#include <sys/types.h>
-
#include <sys/wait.h>
-
-
sig_atomic_t child_exit_status;
-
-
void clean_up_child_process(int signal_number)
-
{
-
int status;
-
wait(&status);
-
-
child_exit_status = status;
-
}
-
-
int main()
-
{
-
struct sigaction sigcichld_action;
-
memset(&sigcichld_action, 0, sizeof(sigcichld_action));
-
sigcichld_action.sa_handler = &clean_up_child_process;
-
sigaction(SIGCHLD, &sigcichld_action, NULL);
-
-
pid_t child_pid;
-
child_pid = fork();
-
if(child_pid > 0) {
-
sleep(60);
-
}
-
else {
-
exit(0);
-
}
-
-
return 0;
-
}
注意信号处理函数中将进程退出代码保存到了全局变量中,从而可以在主程序中访问它。因为这个变量在信号处理函数中被赋值,我们将它声明为 sig_atomic_t 类型。
SIGINT 由ctrl+c产生
SIGTERM 程序中kill 命令产生
SIGABRT abort()函数产生
SIGKILL 操作系统中kill命令调用产生,不能被改写,屏蔽
SIGCHLD 在一个进程终止或者停止时,将SIGCHLD信号发送给其父进程
阅读(1736) | 评论(0) | 转发(0) |