Socket之僵尸进程

僵尸进程是指完成执行,但是仍有一个对应的PCB残留在进程表中,处于终止态的进程

一般而言,僵尸进程会被父进程wait进行回收,如果没有得到回收或者父进程还没退出,那么就会如同zombie一样一直残留

怎么产生

例如在socket中父进程大量地进行fork,并且没有wait,那么子进程结束之后就会变成僵尸进程

如何处理—信号量signal

子进程完成之后,系统会发送SIGCHLD信号给父进程

然而父进程对其默认处理是直接忽略,要想处理僵尸进程,那么需要使用wait来回收

那么如何处理信号量呢?下面我们将对signal(...), wait(...), waitpid(...)等函数进行说明

signal

1
2
3
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
  • signum : 需要处理的信号类型
  • handler : 处理方案

wait & waitpid

1
2
3
#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pd, int *statloc, int options);

当子进程完成,就会发送SIGCHLD信号给父进程,这时候,我们可以通过在handler中调用wait回收僵尸进程

1
2
3
4
5
6
7
8
9
10
#include <signal.h>
#include <sys/wait.h>

void sig_chld(int signo) {
pid_t pid;
int stat;

pid = wait(&stat); //stat用来保存子进程的结束状态
//pid用来保存子进程的id号
}

但是,这个方案存在缺陷,如果在同一时间有多个SIGCHLD传来,那么只会有一个僵尸进程得到回收

因此,正确的解决方案是调用waitpid

1
2
3
4
5
6
7
8
void sig_chld(int signo) {
pid_t pid;
int stat;

while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0) {
printf("chlid %d terminated\n", pid);
}
}