在 CentOS 系统中,僵尸进程的预防可以通过以下几种方法来实现:
signal(SIGCHLD, SIG_IGN)
在父进程中显式调用 signal(SIGCHLD, SIG_IGN)
可以使系统忽略 SIGCHLD
信号,这样子进程结束后,内核会自动回收其资源,不会形成僵尸进程。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, const char* argv[]) {
pid_t pid;
if (sig_err == signal(SIGCHLD, SIG_IGN)) {
perror("signal error");
exit(EXIT_FAILURE);
}
while (1) {
if ((pid = fork()) == 0) { /* child */
_exit(0);
}
}
exit(EXIT_SUCCESS);
}
wait
或 waitpid
在父进程中使用 wait
或 waitpid
函数来等待子进程结束,并回收其资源。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, const char* argv[]) {
pid_t pid;
int status;
while ((pid = fork()) != 0) {
if (pid < 0) {
perror("fork error");
exit(EXIT_FAILURE);
}
// 父进程做一些工作
wait(&status); // 等待子进程结束
}
// 子进程做一些工作
exit(EXIT_SUCCESS);
}
第一次 fork 后的子进程直接退出,这样第二次 fork 得到的子进程没有父进程,会被 init 进程收养,init 进程会负责释放子进程的资源。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char* argv[]) {
pid_t pid;
if ((pid = fork()) == 0) { /* first child */
exit(0);
} else if (pid > 0) { /* parent */
pid_t second_pid = fork();
if (second_pid == 0) { /* second child */
exit(0);
}
// 父进程做一些工作
wait(NULL); // 等待第一个子进程结束
} else {
perror("fork error");
exit(EXIT_FAILURE);
}
return 0;
}
sigaction
替代 signal
使用 sigaction
函数来设置 SIGCHLD
信号的处理函数,可以在信号处理函数中调用 wait
或 waitpid
来回收子进程的资源。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
void handle_sigchld(int sig) {
pid_t status;
while (wait(&status) != -1);
}
int main(int argc, const char* argv[]) {
struct sigaction sa;
sa.sa_handler = handle_sigchld;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction error");
exit(EXIT_FAILURE);
}
// 父进程做一些工作
return 0;
}
使用系统监控工具(如 top
、ps
等)定期检查系统中的进程状态,及时发现并处理僵尸进程。
ps -A -o stat,ppid,pid,cmd | grep -e '[Zz]'
在使用 Docker 等容器技术时,确保容器内的进程管理得当,避免僵尸进程的产生。可以使用 dumb-init
或 tini
作为容器的入口点进程,它们能够接管孤儿进程并回收僵尸进程。
通过以上方法,可以有效预防 CentOS 系统中的僵尸进程问题,确保系统的稳定运行。