在Linux系统中,僵尸进程是指已经结束但仍然在进程表中保留条目的进程。这些进程不再执行任何操作,但它们的父进程尚未读取它们的退出状态,导致它们无法被完全移除。以下是一些避免僵尸进程的方法:
wait()
或waitpid()
来获取子进程的退出状态,导致子进程的进程描述符仍然保留在系统中。wait()
或waitpid()
父进程应该调用wait()
或waitpid()
来等待子进程的结束并回收其资源。
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t pid = fork();
if (pid == 0) { // 子进程
// 执行子进程的任务
exit(0);
} else if (pid > 0) { // 父进程
int status;
wait(&status); // 等待子进程结束并回收资源
// 处理子进程的退出状态
} else {
perror("fork");
return 1;
}
return 0;
}
父进程可以设置一个信号处理函数来捕获SIGCHLD
信号,并在该信号处理函数中调用wait()
或waitpid()
。
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
void sigchld_handler(int signum) {
int status;
while (waitpid(-1, &status, WNOHANG) > 0);
}
int main() {
pid_t pid = fork();
if (pid == 0) { // 子进程
// 执行子进程的任务
exit(0);
} else if (pid > 0) { // 父进程
struct sigaction sa;
sa.sa_handler = sigchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGCHLD, &sa, NULL);
// 父进程继续执行其他任务
while (1) {
sleep(1);
}
} else {
perror("fork");
return 1;
}
return 0;
}
如果父进程不需要关心子进程的退出状态,可以将子进程设置为守护进程。守护进程在启动后会脱离控制终端,并且通常会在后台运行。
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
void daemonize() {
pid_t pid;
// 第一次fork,确保进程不是会话组长
pid = fork();
if (pid < 0) exit(EXIT_FAILURE);
if (pid > 0) exit(EXIT_SUCCESS);
// 创建新的会话
if (setsid() < 0) exit(EXIT_FAILURE);
// 第二次fork,确保进程不是会话组长
pid = fork();
if (pid < 0) exit(EXIT_FAILURE);
if (pid > 0) exit(EXIT_SUCCESS);
// 重定向标准文件描述符
umask(0);
int fd = open("/dev/null", O_RDWR);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > 2) close(fd);
}
int main() {
daemonize();
// 守护进程的任务
while (1) {
// 执行任务
sleep(1);
}
return 0;
}
避免僵尸进程的关键在于确保父进程能够及时回收子进程的资源。通过调用wait()
或waitpid()
,使用信号处理机制,或者将进程设置为守护进程,可以有效减少或消除僵尸进程的出现。
领取专属 10元无门槛券
手把手带您无忧上云